Compare commits
129 Commits
david/allo
...
codex/stab
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
47a5543109 | ||
|
|
55100209c7 | ||
|
|
c0bb83b882 | ||
|
|
74a4e9af3d | ||
|
|
8485dbb324 | ||
|
|
0858896bc4 | ||
|
|
ce8b744f17 | ||
|
|
5a8cdab771 | ||
|
|
3a8191529c | ||
|
|
e658778ced | ||
|
|
f1883d71a4 | ||
|
|
11db567b0b | ||
|
|
9f8c3de462 | ||
|
|
293d4ac388 | ||
|
|
9e8a7e9353 | ||
|
|
453e5f5934 | ||
|
|
7ea773daf2 | ||
|
|
0079cc6817 | ||
|
|
e8ea40012a | ||
|
|
71d8a5da2a | ||
|
|
2c3b3d3230 | ||
|
|
8d98c601d8 | ||
|
|
0986edf427 | ||
|
|
03f1f8e218 | ||
|
|
628bb2cd1d | ||
|
|
f23d2c9b9e | ||
|
|
67d94d9ec8 | ||
|
|
d1cb8e2142 | ||
|
|
57202c1c77 | ||
|
|
2289187b74 | ||
|
|
14c42a8ddf | ||
|
|
e677863787 | ||
|
|
f379eb6e62 | ||
|
|
47698883ae | ||
|
|
e2d96df501 | ||
|
|
384e80ec80 | ||
|
|
b9f3b0e0a6 | ||
|
|
1e6d76c878 | ||
|
|
844c8626c3 | ||
|
|
1c8d9d707e | ||
|
|
4856377478 | ||
|
|
643c845a47 | ||
|
|
9e952cf0e0 | ||
|
|
c4015edf48 | ||
|
|
97b824db3e | ||
|
|
220ab88779 | ||
|
|
7a63ac145a | ||
|
|
54f597658c | ||
|
|
aa1fad61e0 | ||
|
|
b390b3cb8e | ||
|
|
88866f0048 | ||
|
|
9bbf4987e8 | ||
|
|
ad024f9a09 | ||
|
|
fc549bda94 | ||
|
|
77c8ddf101 | ||
|
|
e730f27f80 | ||
|
|
d65bd69963 | ||
|
|
c713e76e4d | ||
|
|
8005ebb405 | ||
|
|
0c29e258c6 | ||
|
|
b5b6b657cc | ||
|
|
ad2f667ee4 | ||
|
|
363f061f09 | ||
|
|
9b0dfc505f | ||
|
|
695de4f27f | ||
|
|
3445d1322d | ||
|
|
2c3f091e0e | ||
|
|
9d3cad95bc | ||
|
|
7df79cfb70 | ||
|
|
33ed502edb | ||
|
|
a827b16ebd | ||
|
|
47a2ec002e | ||
|
|
aee3af0f7a | ||
|
|
04dc48e17c | ||
|
|
27743efa1b | ||
|
|
c60b4d7f30 | ||
|
|
16621fa19d | ||
|
|
e23d4ea027 | ||
|
|
452f992fbc | ||
|
|
a5ebb3f3a2 | ||
|
|
9925910a29 | ||
|
|
a3ee6bb3b5 | ||
|
|
b60ba75d09 | ||
|
|
66ba1d8775 | ||
|
|
bbcd7e0196 | ||
|
|
48c425c15b | ||
|
|
6d210dd0c7 | ||
|
|
9ce83c215d | ||
|
|
602dd5c039 | ||
|
|
3eada01153 | ||
|
|
3e811fc369 | ||
|
|
743764d384 | ||
|
|
e03e05d2b3 | ||
|
|
9ec4a178a4 | ||
|
|
8d5655a7ba | ||
|
|
6453ac9ea1 | ||
|
|
0a11baf29c | ||
|
|
1d20cf9570 | ||
|
|
62ef96f51e | ||
|
|
4e68dd96a6 | ||
|
|
b25b642371 | ||
|
|
175402aa75 | ||
|
|
d8216fa328 | ||
|
|
d51f6940fe | ||
|
|
66b082ff71 | ||
|
|
5d93d619f3 | ||
|
|
e1b662bf5d | ||
|
|
f885cb8a2f | ||
|
|
4ef2c223c9 | ||
|
|
d078ecff37 | ||
|
|
7eca6f96e3 | ||
|
|
fbaf826a9d | ||
|
|
d8a5b9de17 | ||
|
|
c3feb8ce27 | ||
|
|
97ff015c88 | ||
|
|
1f7134f727 | ||
|
|
6a0b93170e | ||
|
|
cc59ff8aad | ||
|
|
2b90e7fcd7 | ||
|
|
a43f5b2129 | ||
|
|
f3fb7429ca | ||
|
|
83498b95fb | ||
|
|
03d7be3747 | ||
|
|
d95b029862 | ||
|
|
14c3755445 | ||
|
|
83a036960b | ||
|
|
be76fadb05 | ||
|
|
e293411679 | ||
|
|
53d19f8368 |
4
.github/workflows/build-docker.yml
vendored
4
.github/workflows/build-docker.yml
vendored
@@ -79,7 +79,7 @@ jobs:
|
|||||||
# Adapted from https://docs.docker.com/build/ci/github-actions/multi-platform/
|
# Adapted from https://docs.docker.com/build/ci/github-actions/multi-platform/
|
||||||
- name: Build and push by digest
|
- name: Build and push by digest
|
||||||
id: build
|
id: build
|
||||||
uses: docker/build-push-action@1dc73863535b631f98b2378be8619f83b136f4a0 # v6.17.0
|
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
platforms: ${{ matrix.platform }}
|
platforms: ${{ matrix.platform }}
|
||||||
@@ -231,7 +231,7 @@ jobs:
|
|||||||
${{ env.TAG_PATTERNS }}
|
${{ env.TAG_PATTERNS }}
|
||||||
|
|
||||||
- name: Build and push
|
- name: Build and push
|
||||||
uses: docker/build-push-action@1dc73863535b631f98b2378be8619f83b136f4a0 # v6.17.0
|
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
platforms: linux/amd64,linux/arm64
|
platforms: linux/amd64,linux/arm64
|
||||||
|
|||||||
36
.github/workflows/ci.yaml
vendored
36
.github/workflows/ci.yaml
vendored
@@ -237,13 +237,13 @@ jobs:
|
|||||||
- name: "Install Rust toolchain"
|
- name: "Install Rust toolchain"
|
||||||
run: rustup show
|
run: rustup show
|
||||||
- name: "Install mold"
|
- name: "Install mold"
|
||||||
uses: rui314/setup-mold@e16410e7f8d9e167b74ad5697a9089a35126eb50 # v1
|
uses: rui314/setup-mold@67424c1b3680e35255d95971cbd5de0047bf31c3 # v1
|
||||||
- name: "Install cargo nextest"
|
- name: "Install cargo nextest"
|
||||||
uses: taiki-e/install-action@941e8a4d9d7cdb696bd4f017cf54aca281f8ffff # v2.51.2
|
uses: taiki-e/install-action@735e5933943122c5ac182670a935f54a949265c1 # v2.52.4
|
||||||
with:
|
with:
|
||||||
tool: cargo-nextest
|
tool: cargo-nextest
|
||||||
- name: "Install cargo insta"
|
- name: "Install cargo insta"
|
||||||
uses: taiki-e/install-action@941e8a4d9d7cdb696bd4f017cf54aca281f8ffff # v2.51.2
|
uses: taiki-e/install-action@735e5933943122c5ac182670a935f54a949265c1 # v2.52.4
|
||||||
with:
|
with:
|
||||||
tool: cargo-insta
|
tool: cargo-insta
|
||||||
- name: ty mdtests (GitHub annotations)
|
- name: ty mdtests (GitHub annotations)
|
||||||
@@ -295,13 +295,13 @@ jobs:
|
|||||||
- name: "Install Rust toolchain"
|
- name: "Install Rust toolchain"
|
||||||
run: rustup show
|
run: rustup show
|
||||||
- name: "Install mold"
|
- name: "Install mold"
|
||||||
uses: rui314/setup-mold@e16410e7f8d9e167b74ad5697a9089a35126eb50 # v1
|
uses: rui314/setup-mold@67424c1b3680e35255d95971cbd5de0047bf31c3 # v1
|
||||||
- name: "Install cargo nextest"
|
- name: "Install cargo nextest"
|
||||||
uses: taiki-e/install-action@941e8a4d9d7cdb696bd4f017cf54aca281f8ffff # v2.51.2
|
uses: taiki-e/install-action@735e5933943122c5ac182670a935f54a949265c1 # v2.52.4
|
||||||
with:
|
with:
|
||||||
tool: cargo-nextest
|
tool: cargo-nextest
|
||||||
- name: "Install cargo insta"
|
- name: "Install cargo insta"
|
||||||
uses: taiki-e/install-action@941e8a4d9d7cdb696bd4f017cf54aca281f8ffff # v2.51.2
|
uses: taiki-e/install-action@735e5933943122c5ac182670a935f54a949265c1 # v2.52.4
|
||||||
with:
|
with:
|
||||||
tool: cargo-insta
|
tool: cargo-insta
|
||||||
- name: "Run tests"
|
- name: "Run tests"
|
||||||
@@ -324,7 +324,7 @@ jobs:
|
|||||||
- name: "Install Rust toolchain"
|
- name: "Install Rust toolchain"
|
||||||
run: rustup show
|
run: rustup show
|
||||||
- name: "Install cargo nextest"
|
- name: "Install cargo nextest"
|
||||||
uses: taiki-e/install-action@941e8a4d9d7cdb696bd4f017cf54aca281f8ffff # v2.51.2
|
uses: taiki-e/install-action@735e5933943122c5ac182670a935f54a949265c1 # v2.52.4
|
||||||
with:
|
with:
|
||||||
tool: cargo-nextest
|
tool: cargo-nextest
|
||||||
- name: "Run tests"
|
- name: "Run tests"
|
||||||
@@ -380,7 +380,7 @@ jobs:
|
|||||||
- name: "Install Rust toolchain"
|
- name: "Install Rust toolchain"
|
||||||
run: rustup show
|
run: rustup show
|
||||||
- name: "Install mold"
|
- name: "Install mold"
|
||||||
uses: rui314/setup-mold@e16410e7f8d9e167b74ad5697a9089a35126eb50 # v1
|
uses: rui314/setup-mold@67424c1b3680e35255d95971cbd5de0047bf31c3 # v1
|
||||||
- name: "Build"
|
- name: "Build"
|
||||||
run: cargo build --release --locked
|
run: cargo build --release --locked
|
||||||
|
|
||||||
@@ -405,13 +405,13 @@ jobs:
|
|||||||
MSRV: ${{ steps.msrv.outputs.value }}
|
MSRV: ${{ steps.msrv.outputs.value }}
|
||||||
run: rustup default "${MSRV}"
|
run: rustup default "${MSRV}"
|
||||||
- name: "Install mold"
|
- name: "Install mold"
|
||||||
uses: rui314/setup-mold@e16410e7f8d9e167b74ad5697a9089a35126eb50 # v1
|
uses: rui314/setup-mold@67424c1b3680e35255d95971cbd5de0047bf31c3 # v1
|
||||||
- name: "Install cargo nextest"
|
- name: "Install cargo nextest"
|
||||||
uses: taiki-e/install-action@941e8a4d9d7cdb696bd4f017cf54aca281f8ffff # v2.51.2
|
uses: taiki-e/install-action@735e5933943122c5ac182670a935f54a949265c1 # v2.52.4
|
||||||
with:
|
with:
|
||||||
tool: cargo-nextest
|
tool: cargo-nextest
|
||||||
- name: "Install cargo insta"
|
- name: "Install cargo insta"
|
||||||
uses: taiki-e/install-action@941e8a4d9d7cdb696bd4f017cf54aca281f8ffff # v2.51.2
|
uses: taiki-e/install-action@735e5933943122c5ac182670a935f54a949265c1 # v2.52.4
|
||||||
with:
|
with:
|
||||||
tool: cargo-insta
|
tool: cargo-insta
|
||||||
- name: "Run tests"
|
- name: "Run tests"
|
||||||
@@ -437,7 +437,7 @@ jobs:
|
|||||||
- name: "Install Rust toolchain"
|
- name: "Install Rust toolchain"
|
||||||
run: rustup show
|
run: rustup show
|
||||||
- name: "Install cargo-binstall"
|
- name: "Install cargo-binstall"
|
||||||
uses: cargo-bins/cargo-binstall@5cbf019d8cb9b9d5b086218c41458ea35d817691 # v1.12.5
|
uses: cargo-bins/cargo-binstall@e8c9cc3599f6c4063d143083205f98ca25d91677 # v1.12.6
|
||||||
with:
|
with:
|
||||||
tool: cargo-fuzz@0.11.2
|
tool: cargo-fuzz@0.11.2
|
||||||
- name: "Install cargo-fuzz"
|
- name: "Install cargo-fuzz"
|
||||||
@@ -459,7 +459,7 @@ jobs:
|
|||||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- uses: astral-sh/setup-uv@6b9c6063abd6010835644d4c2e1bef4cf5cd0fca # v6.0.1
|
- uses: astral-sh/setup-uv@f0ec1fc3b38f5e7cd731bb6ce540c5af426746bb # v6.1.0
|
||||||
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
|
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
|
||||||
name: Download Ruff binary to test
|
name: Download Ruff binary to test
|
||||||
id: download-cached-binary
|
id: download-cached-binary
|
||||||
@@ -660,7 +660,7 @@ jobs:
|
|||||||
branch: ${{ github.event.pull_request.base.ref }}
|
branch: ${{ github.event.pull_request.base.ref }}
|
||||||
workflow: "ci.yaml"
|
workflow: "ci.yaml"
|
||||||
check_artifacts: true
|
check_artifacts: true
|
||||||
- uses: astral-sh/setup-uv@6b9c6063abd6010835644d4c2e1bef4cf5cd0fca # v6.0.1
|
- uses: astral-sh/setup-uv@f0ec1fc3b38f5e7cd731bb6ce540c5af426746bb # v6.1.0
|
||||||
- name: Fuzz
|
- name: Fuzz
|
||||||
env:
|
env:
|
||||||
FORCE_COLOR: 1
|
FORCE_COLOR: 1
|
||||||
@@ -690,7 +690,7 @@ jobs:
|
|||||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- uses: cargo-bins/cargo-binstall@5cbf019d8cb9b9d5b086218c41458ea35d817691 # v1.12.5
|
- uses: cargo-bins/cargo-binstall@e8c9cc3599f6c4063d143083205f98ca25d91677 # v1.12.6
|
||||||
- run: cargo binstall --no-confirm cargo-shear
|
- run: cargo binstall --no-confirm cargo-shear
|
||||||
- run: cargo shear
|
- run: cargo shear
|
||||||
|
|
||||||
@@ -730,7 +730,7 @@ jobs:
|
|||||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- uses: astral-sh/setup-uv@6b9c6063abd6010835644d4c2e1bef4cf5cd0fca # v6.0.1
|
- uses: astral-sh/setup-uv@f0ec1fc3b38f5e7cd731bb6ce540c5af426746bb # v6.1.0
|
||||||
- uses: Swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 # v2.7.8
|
- uses: Swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 # v2.7.8
|
||||||
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
||||||
with:
|
with:
|
||||||
@@ -773,7 +773,7 @@ jobs:
|
|||||||
- name: "Install Rust toolchain"
|
- name: "Install Rust toolchain"
|
||||||
run: rustup show
|
run: rustup show
|
||||||
- name: Install uv
|
- name: Install uv
|
||||||
uses: astral-sh/setup-uv@6b9c6063abd6010835644d4c2e1bef4cf5cd0fca # v6.0.1
|
uses: astral-sh/setup-uv@f0ec1fc3b38f5e7cd731bb6ce540c5af426746bb # v6.1.0
|
||||||
- name: "Install Insiders dependencies"
|
- name: "Install Insiders dependencies"
|
||||||
if: ${{ env.MKDOCS_INSIDERS_SSH_KEY_EXISTS == 'true' }}
|
if: ${{ env.MKDOCS_INSIDERS_SSH_KEY_EXISTS == 'true' }}
|
||||||
run: uv pip install -r docs/requirements-insiders.txt --system
|
run: uv pip install -r docs/requirements-insiders.txt --system
|
||||||
@@ -910,7 +910,7 @@ jobs:
|
|||||||
run: rustup show
|
run: rustup show
|
||||||
|
|
||||||
- name: "Install codspeed"
|
- name: "Install codspeed"
|
||||||
uses: taiki-e/install-action@941e8a4d9d7cdb696bd4f017cf54aca281f8ffff # v2.51.2
|
uses: taiki-e/install-action@735e5933943122c5ac182670a935f54a949265c1 # v2.52.4
|
||||||
with:
|
with:
|
||||||
tool: cargo-codspeed
|
tool: cargo-codspeed
|
||||||
|
|
||||||
|
|||||||
4
.github/workflows/daily_fuzz.yaml
vendored
4
.github/workflows/daily_fuzz.yaml
vendored
@@ -34,11 +34,11 @@ jobs:
|
|||||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- uses: astral-sh/setup-uv@6b9c6063abd6010835644d4c2e1bef4cf5cd0fca # v6.0.1
|
- uses: astral-sh/setup-uv@f0ec1fc3b38f5e7cd731bb6ce540c5af426746bb # v6.1.0
|
||||||
- name: "Install Rust toolchain"
|
- name: "Install Rust toolchain"
|
||||||
run: rustup show
|
run: rustup show
|
||||||
- name: "Install mold"
|
- name: "Install mold"
|
||||||
uses: rui314/setup-mold@e16410e7f8d9e167b74ad5697a9089a35126eb50 # v1
|
uses: rui314/setup-mold@67424c1b3680e35255d95971cbd5de0047bf31c3 # v1
|
||||||
- uses: Swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 # v2.7.8
|
- uses: Swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 # v2.7.8
|
||||||
- name: Build ruff
|
- name: Build ruff
|
||||||
# A debug build means the script runs slower once it gets started,
|
# A debug build means the script runs slower once it gets started,
|
||||||
|
|||||||
2
.github/workflows/mypy_primer.yaml
vendored
2
.github/workflows/mypy_primer.yaml
vendored
@@ -37,7 +37,7 @@ jobs:
|
|||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
- name: Install the latest version of uv
|
- name: Install the latest version of uv
|
||||||
uses: astral-sh/setup-uv@6b9c6063abd6010835644d4c2e1bef4cf5cd0fca # v6.0.1
|
uses: astral-sh/setup-uv@f0ec1fc3b38f5e7cd731bb6ce540c5af426746bb # v6.1.0
|
||||||
|
|
||||||
- uses: Swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 # v2.7.8
|
- uses: Swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 # v2.7.8
|
||||||
with:
|
with:
|
||||||
|
|||||||
2
.github/workflows/publish-pypi.yml
vendored
2
.github/workflows/publish-pypi.yml
vendored
@@ -22,7 +22,7 @@ jobs:
|
|||||||
id-token: write
|
id-token: write
|
||||||
steps:
|
steps:
|
||||||
- name: "Install uv"
|
- name: "Install uv"
|
||||||
uses: astral-sh/setup-uv@6b9c6063abd6010835644d4c2e1bef4cf5cd0fca # v6.0.1
|
uses: astral-sh/setup-uv@f0ec1fc3b38f5e7cd731bb6ce540c5af426746bb # v6.1.0
|
||||||
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
|
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
|
||||||
with:
|
with:
|
||||||
pattern: wheels-*
|
pattern: wheels-*
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ repos:
|
|||||||
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
|
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||||
rev: v0.11.10
|
rev: v0.11.12
|
||||||
hooks:
|
hooks:
|
||||||
- id: ruff-format
|
- id: ruff-format
|
||||||
- id: ruff
|
- id: ruff
|
||||||
@@ -98,7 +98,7 @@ repos:
|
|||||||
# zizmor detects security vulnerabilities in GitHub Actions workflows.
|
# zizmor detects security vulnerabilities in GitHub Actions workflows.
|
||||||
# Additional configuration for the tool is found in `.github/zizmor.yml`
|
# Additional configuration for the tool is found in `.github/zizmor.yml`
|
||||||
- repo: https://github.com/woodruffw/zizmor-pre-commit
|
- repo: https://github.com/woodruffw/zizmor-pre-commit
|
||||||
rev: v1.7.0
|
rev: v1.9.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: zizmor
|
- id: zizmor
|
||||||
|
|
||||||
|
|||||||
28
CHANGELOG.md
28
CHANGELOG.md
@@ -1,5 +1,33 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 0.11.12
|
||||||
|
|
||||||
|
### Preview features
|
||||||
|
|
||||||
|
- \[`airflow`\] Revise fix titles (`AIR3`) ([#18215](https://github.com/astral-sh/ruff/pull/18215))
|
||||||
|
- \[`pylint`\] Implement `missing-maxsplit-arg` (`PLC0207`) ([#17454](https://github.com/astral-sh/ruff/pull/17454))
|
||||||
|
- \[`pyupgrade`\] New rule `UP050` (`useless-class-metaclass-type`) ([#18334](https://github.com/astral-sh/ruff/pull/18334))
|
||||||
|
- \[`flake8-use-pathlib`\] Replace `os.symlink` with `Path.symlink_to` (`PTH211`) ([#18337](https://github.com/astral-sh/ruff/pull/18337))
|
||||||
|
|
||||||
|
### Bug fixes
|
||||||
|
|
||||||
|
- \[`flake8-bugbear`\] Ignore `__debug__` attribute in `B010` ([#18357](https://github.com/astral-sh/ruff/pull/18357))
|
||||||
|
- \[`flake8-async`\] Fix `anyio.sleep` argument name (`ASYNC115`, `ASYNC116`) ([#18262](https://github.com/astral-sh/ruff/pull/18262))
|
||||||
|
- \[`refurb`\] Fix `FURB129` autofix generating invalid syntax ([#18235](https://github.com/astral-sh/ruff/pull/18235))
|
||||||
|
|
||||||
|
### Rule changes
|
||||||
|
|
||||||
|
- \[`flake8-implicit-str-concat`\] Add autofix for `ISC003` ([#18256](https://github.com/astral-sh/ruff/pull/18256))
|
||||||
|
- \[`pycodestyle`\] Improve the diagnostic message for `E712` ([#18328](https://github.com/astral-sh/ruff/pull/18328))
|
||||||
|
- \[`flake8-2020`\] Fix diagnostic message for `!=` comparisons (`YTT201`) ([#18293](https://github.com/astral-sh/ruff/pull/18293))
|
||||||
|
- \[`pyupgrade`\] Make fix unsafe if it deletes comments (`UP010`) ([#18291](https://github.com/astral-sh/ruff/pull/18291))
|
||||||
|
|
||||||
|
### Documentation
|
||||||
|
|
||||||
|
- Simplify rules table to improve readability ([#18297](https://github.com/astral-sh/ruff/pull/18297))
|
||||||
|
- Update editor integrations link in README ([#17977](https://github.com/astral-sh/ruff/pull/17977))
|
||||||
|
- \[`flake8-bugbear`\] Add fix safety section (`B006`) ([#17652](https://github.com/astral-sh/ruff/pull/17652))
|
||||||
|
|
||||||
## 0.11.11
|
## 0.11.11
|
||||||
|
|
||||||
### Preview features
|
### Preview features
|
||||||
|
|||||||
77
Cargo.lock
generated
77
Cargo.lock
generated
@@ -8,6 +8,18 @@ version = "2.0.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
|
checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ahash"
|
||||||
|
version = "0.8.12"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"once_cell",
|
||||||
|
"version_check",
|
||||||
|
"zerocopy",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "aho-corasick"
|
name = "aho-corasick"
|
||||||
version = "1.1.3"
|
version = "1.1.3"
|
||||||
@@ -342,9 +354,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap"
|
name = "clap"
|
||||||
version = "4.5.38"
|
version = "4.5.39"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ed93b9805f8ba930df42c2590f05453d5ec36cbb85d018868a5b24d31f6ac000"
|
checksum = "fd60e63e9be68e5fb56422e397cf9baddded06dae1d2e523401542383bc72a9f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap_builder",
|
"clap_builder",
|
||||||
"clap_derive",
|
"clap_derive",
|
||||||
@@ -352,9 +364,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap_builder"
|
name = "clap_builder"
|
||||||
version = "4.5.38"
|
version = "4.5.39"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "379026ff283facf611b0ea629334361c4211d1b12ee01024eec1591133b04120"
|
checksum = "89cc6392a1f72bbeb820d71f32108f61fdaf18bc526e1d23954168a67759ef51"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anstream",
|
"anstream",
|
||||||
"anstyle",
|
"anstyle",
|
||||||
@@ -1106,6 +1118,10 @@ name = "hashbrown"
|
|||||||
version = "0.14.5"
|
version = "0.14.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
|
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
|
||||||
|
dependencies = [
|
||||||
|
"ahash",
|
||||||
|
"allocator-api2",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hashbrown"
|
name = "hashbrown"
|
||||||
@@ -1498,9 +1514,9 @@ checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "jiff"
|
name = "jiff"
|
||||||
version = "0.2.13"
|
version = "0.2.14"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f02000660d30638906021176af16b17498bd0d12813dbfe7b276d8bc7f3c0806"
|
checksum = "a194df1107f33c79f4f93d02c80798520551949d59dfad22b6157048a88cca93"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"jiff-static",
|
"jiff-static",
|
||||||
"jiff-tzdb-platform",
|
"jiff-tzdb-platform",
|
||||||
@@ -1513,9 +1529,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "jiff-static"
|
name = "jiff-static"
|
||||||
version = "0.2.13"
|
version = "0.2.14"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f3c30758ddd7188629c6713fc45d1188af4f44c90582311d0c8d8c9907f60c48"
|
checksum = "6c6e1db7ed32c6c71b759497fae34bf7933636f75a251b9e736555da426f6442"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@@ -1597,9 +1613,9 @@ checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libcst"
|
name = "libcst"
|
||||||
version = "1.7.0"
|
version = "1.8.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ad9e315e3f679e61b9095ffd5e509de78b8a4ea3bba9d772f6fb243209f808d4"
|
checksum = "3ac076e37f8fe6bcddbb6c3282897e6e9498b254907ccbfc806dc8f9f1491f02"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"annotate-snippets",
|
"annotate-snippets",
|
||||||
"libcst_derive",
|
"libcst_derive",
|
||||||
@@ -1607,14 +1623,14 @@ dependencies = [
|
|||||||
"paste",
|
"paste",
|
||||||
"peg",
|
"peg",
|
||||||
"regex",
|
"regex",
|
||||||
"thiserror 1.0.69",
|
"thiserror 2.0.12",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libcst_derive"
|
name = "libcst_derive"
|
||||||
version = "1.7.0"
|
version = "1.8.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bfa96ed35d0dccc67cf7ba49350cb86de3dcb1d072a7ab28f99117f19d874953"
|
checksum = "9cf4a12c744a301b216c4f0cb73542709ab15e6dadbb06966ac05864109d05da"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn",
|
||||||
@@ -2485,7 +2501,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ruff"
|
name = "ruff"
|
||||||
version = "0.11.11"
|
version = "0.11.12"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"argfile",
|
"argfile",
|
||||||
@@ -2642,7 +2658,6 @@ dependencies = [
|
|||||||
"rayon",
|
"rayon",
|
||||||
"regex",
|
"regex",
|
||||||
"ruff",
|
"ruff",
|
||||||
"ruff_diagnostics",
|
|
||||||
"ruff_formatter",
|
"ruff_formatter",
|
||||||
"ruff_linter",
|
"ruff_linter",
|
||||||
"ruff_notebook",
|
"ruff_notebook",
|
||||||
@@ -2672,9 +2687,7 @@ dependencies = [
|
|||||||
name = "ruff_diagnostics"
|
name = "ruff_diagnostics"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
|
||||||
"is-macro",
|
"is-macro",
|
||||||
"log",
|
|
||||||
"ruff_text_size",
|
"ruff_text_size",
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
@@ -2725,7 +2738,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ruff_linter"
|
name = "ruff_linter"
|
||||||
version = "0.11.11"
|
version = "0.11.12"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aho-corasick",
|
"aho-corasick",
|
||||||
"anyhow",
|
"anyhow",
|
||||||
@@ -3061,7 +3074,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ruff_wasm"
|
name = "ruff_wasm"
|
||||||
version = "0.11.11"
|
version = "0.11.12"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"console_error_panic_hook",
|
"console_error_panic_hook",
|
||||||
"console_log",
|
"console_log",
|
||||||
@@ -3081,6 +3094,7 @@ dependencies = [
|
|||||||
"ruff_workspace",
|
"ruff_workspace",
|
||||||
"serde",
|
"serde",
|
||||||
"serde-wasm-bindgen",
|
"serde-wasm-bindgen",
|
||||||
|
"uuid",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
"wasm-bindgen-test",
|
"wasm-bindgen-test",
|
||||||
]
|
]
|
||||||
@@ -3179,13 +3193,14 @@ checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "salsa"
|
name = "salsa"
|
||||||
version = "0.21.1"
|
version = "0.22.0"
|
||||||
source = "git+https://github.com/salsa-rs/salsa.git?rev=4818b15f3b7516555d39f5a41cb75970448bee4c#4818b15f3b7516555d39f5a41cb75970448bee4c"
|
source = "git+https://github.com/carljm/salsa.git?rev=0f6d406f6c309964279baef71588746b8c67b4a3#0f6d406f6c309964279baef71588746b8c67b4a3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"boxcar",
|
"boxcar",
|
||||||
"compact_str",
|
"compact_str",
|
||||||
"crossbeam-queue",
|
"crossbeam-queue",
|
||||||
"dashmap 6.1.0",
|
"dashmap 6.1.0",
|
||||||
|
"hashbrown 0.14.5",
|
||||||
"hashbrown 0.15.3",
|
"hashbrown 0.15.3",
|
||||||
"hashlink",
|
"hashlink",
|
||||||
"indexmap",
|
"indexmap",
|
||||||
@@ -3202,15 +3217,14 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "salsa-macro-rules"
|
name = "salsa-macro-rules"
|
||||||
version = "0.21.1"
|
version = "0.22.0"
|
||||||
source = "git+https://github.com/salsa-rs/salsa.git?rev=4818b15f3b7516555d39f5a41cb75970448bee4c#4818b15f3b7516555d39f5a41cb75970448bee4c"
|
source = "git+https://github.com/carljm/salsa.git?rev=0f6d406f6c309964279baef71588746b8c67b4a3#0f6d406f6c309964279baef71588746b8c67b4a3"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "salsa-macros"
|
name = "salsa-macros"
|
||||||
version = "0.21.1"
|
version = "0.22.0"
|
||||||
source = "git+https://github.com/salsa-rs/salsa.git?rev=4818b15f3b7516555d39f5a41cb75970448bee4c#4818b15f3b7516555d39f5a41cb75970448bee4c"
|
source = "git+https://github.com/carljm/salsa.git?rev=0f6d406f6c309964279baef71588746b8c67b4a3#0f6d406f6c309964279baef71588746b8c67b4a3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"heck",
|
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn",
|
||||||
@@ -3874,6 +3888,7 @@ dependencies = [
|
|||||||
"countme",
|
"countme",
|
||||||
"crossbeam",
|
"crossbeam",
|
||||||
"ctrlc",
|
"ctrlc",
|
||||||
|
"dunce",
|
||||||
"filetime",
|
"filetime",
|
||||||
"indicatif",
|
"indicatif",
|
||||||
"insta",
|
"insta",
|
||||||
@@ -4003,6 +4018,7 @@ dependencies = [
|
|||||||
"ruff_source_file",
|
"ruff_source_file",
|
||||||
"ruff_text_size",
|
"ruff_text_size",
|
||||||
"rustc-hash 2.1.1",
|
"rustc-hash 2.1.1",
|
||||||
|
"salsa",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"shellexpand",
|
"shellexpand",
|
||||||
@@ -4071,6 +4087,7 @@ dependencies = [
|
|||||||
"ty_ide",
|
"ty_ide",
|
||||||
"ty_project",
|
"ty_project",
|
||||||
"ty_python_semantic",
|
"ty_python_semantic",
|
||||||
|
"uuid",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
"wasm-bindgen-test",
|
"wasm-bindgen-test",
|
||||||
]
|
]
|
||||||
@@ -4240,9 +4257,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uuid"
|
name = "uuid"
|
||||||
version = "1.16.0"
|
version = "1.17.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "458f7a779bf54acc9f347480ac654f68407d3aab21269a6e3c9f922acd9e2da9"
|
checksum = "3cf4199d1e5d15ddd86a694e4d0dffa9c323ce759fea589f00fef9d81cc1931d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"getrandom 0.3.3",
|
"getrandom 0.3.3",
|
||||||
"js-sys",
|
"js-sys",
|
||||||
@@ -4253,9 +4270,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uuid-macro-internal"
|
name = "uuid-macro-internal"
|
||||||
version = "1.16.0"
|
version = "1.17.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "72dcd78c4f979627a754f5522cea6e6a25e55139056535fe6e69c506cd64a862"
|
checksum = "26b682e8c381995ea03130e381928e0e005b7c9eb483c6c8682f50e07b33c2b7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
|||||||
@@ -129,7 +129,7 @@ regex = { version = "1.10.2" }
|
|||||||
rustc-hash = { version = "2.0.0" }
|
rustc-hash = { version = "2.0.0" }
|
||||||
rustc-stable-hash = { version = "0.1.2" }
|
rustc-stable-hash = { version = "0.1.2" }
|
||||||
# When updating salsa, make sure to also update the revision in `fuzz/Cargo.toml`
|
# When updating salsa, make sure to also update the revision in `fuzz/Cargo.toml`
|
||||||
salsa = { git = "https://github.com/salsa-rs/salsa.git", rev = "4818b15f3b7516555d39f5a41cb75970448bee4c" }
|
salsa = { git = "https://github.com/carljm/salsa.git", rev = "0f6d406f6c309964279baef71588746b8c67b4a3" }
|
||||||
schemars = { version = "0.8.16" }
|
schemars = { version = "0.8.16" }
|
||||||
seahash = { version = "4.1.0" }
|
seahash = { version = "4.1.0" }
|
||||||
serde = { version = "1.0.197", features = ["derive"] }
|
serde = { version = "1.0.197", features = ["derive"] }
|
||||||
@@ -179,7 +179,6 @@ uuid = { version = "1.6.1", features = [
|
|||||||
"v4",
|
"v4",
|
||||||
"fast-rng",
|
"fast-rng",
|
||||||
"macro-diagnostics",
|
"macro-diagnostics",
|
||||||
"js",
|
|
||||||
] }
|
] }
|
||||||
walkdir = { version = "2.3.2" }
|
walkdir = { version = "2.3.2" }
|
||||||
wasm-bindgen = { version = "0.2.92" }
|
wasm-bindgen = { version = "0.2.92" }
|
||||||
@@ -188,7 +187,7 @@ wild = { version = "2" }
|
|||||||
zip = { version = "0.6.6", default-features = false }
|
zip = { version = "0.6.6", default-features = false }
|
||||||
|
|
||||||
[workspace.metadata.cargo-shear]
|
[workspace.metadata.cargo-shear]
|
||||||
ignored = ["getrandom", "ruff_options_metadata"]
|
ignored = ["getrandom", "ruff_options_metadata", "uuid"]
|
||||||
|
|
||||||
|
|
||||||
[workspace.lints.rust]
|
[workspace.lints.rust]
|
||||||
|
|||||||
@@ -34,8 +34,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 [800 built-in rules](https://docs.astral.sh/ruff/rules/), with native re-implementations
|
- 📏 Over [800 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/integrations/) for
|
- ⌨️ First-party [editor integrations](https://docs.astral.sh/ruff/editors) for [VS Code](https://github.com/astral-sh/ruff-vscode) and [more](https://docs.astral.sh/ruff/editors/setup)
|
||||||
[VS Code](https://github.com/astral-sh/ruff-vscode) and [more](https://docs.astral.sh/ruff/editors/setup)
|
|
||||||
- 🌎 Monorepo-friendly, with [hierarchical and cascading configuration](https://docs.astral.sh/ruff/configuration/#config-file-discovery)
|
- 🌎 Monorepo-friendly, with [hierarchical and cascading configuration](https://docs.astral.sh/ruff/configuration/#config-file-discovery)
|
||||||
|
|
||||||
Ruff aims to be orders of magnitude faster than alternative tools while integrating more
|
Ruff aims to be orders of magnitude faster than alternative tools while integrating more
|
||||||
@@ -149,8 +148,8 @@ curl -LsSf https://astral.sh/ruff/install.sh | sh
|
|||||||
powershell -c "irm https://astral.sh/ruff/install.ps1 | iex"
|
powershell -c "irm https://astral.sh/ruff/install.ps1 | iex"
|
||||||
|
|
||||||
# For a specific version.
|
# For a specific version.
|
||||||
curl -LsSf https://astral.sh/ruff/0.11.11/install.sh | sh
|
curl -LsSf https://astral.sh/ruff/0.11.12/install.sh | sh
|
||||||
powershell -c "irm https://astral.sh/ruff/0.11.11/install.ps1 | iex"
|
powershell -c "irm https://astral.sh/ruff/0.11.12/install.ps1 | iex"
|
||||||
```
|
```
|
||||||
|
|
||||||
You can also install Ruff via [Homebrew](https://formulae.brew.sh/formula/ruff), [Conda](https://anaconda.org/conda-forge/ruff),
|
You can also install Ruff via [Homebrew](https://formulae.brew.sh/formula/ruff), [Conda](https://anaconda.org/conda-forge/ruff),
|
||||||
@@ -183,7 +182,7 @@ Ruff can also be used as a [pre-commit](https://pre-commit.com/) hook via [`ruff
|
|||||||
```yaml
|
```yaml
|
||||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||||
# Ruff version.
|
# Ruff version.
|
||||||
rev: v0.11.11
|
rev: v0.11.12
|
||||||
hooks:
|
hooks:
|
||||||
# Run the linter.
|
# Run the linter.
|
||||||
- id: ruff
|
- id: ruff
|
||||||
|
|||||||
@@ -4,6 +4,10 @@ extend-exclude = [
|
|||||||
"crates/ty_vendored/vendor/**/*",
|
"crates/ty_vendored/vendor/**/*",
|
||||||
"**/resources/**/*",
|
"**/resources/**/*",
|
||||||
"**/snapshots/**/*",
|
"**/snapshots/**/*",
|
||||||
|
# Completion tests tend to have a lot of incomplete
|
||||||
|
# words naturally. It's annoying to have to make all
|
||||||
|
# of them actually words. So just ignore typos here.
|
||||||
|
"crates/ty_ide/src/completion.rs",
|
||||||
]
|
]
|
||||||
|
|
||||||
[default.extend-words]
|
[default.extend-words]
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "ruff"
|
name = "ruff"
|
||||||
version = "0.11.11"
|
version = "0.11.12"
|
||||||
publish = true
|
publish = true
|
||||||
authors = { workspace = true }
|
authors = { workspace = true }
|
||||||
edition = { workspace = true }
|
edition = { workspace = true }
|
||||||
|
|||||||
@@ -349,7 +349,6 @@ impl FileCache {
|
|||||||
.iter()
|
.iter()
|
||||||
.map(|msg| {
|
.map(|msg| {
|
||||||
Message::diagnostic(
|
Message::diagnostic(
|
||||||
msg.rule.into(),
|
|
||||||
msg.body.clone(),
|
msg.body.clone(),
|
||||||
msg.suggestion.clone(),
|
msg.suggestion.clone(),
|
||||||
msg.range,
|
msg.range,
|
||||||
@@ -357,6 +356,7 @@ impl FileCache {
|
|||||||
msg.parent,
|
msg.parent,
|
||||||
file.clone(),
|
file.clone(),
|
||||||
msg.noqa_offset,
|
msg.noqa_offset,
|
||||||
|
msg.rule,
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ use rayon::prelude::*;
|
|||||||
use rustc_hash::FxHashMap;
|
use rustc_hash::FxHashMap;
|
||||||
|
|
||||||
use ruff_db::panic::catch_unwind;
|
use ruff_db::panic::catch_unwind;
|
||||||
use ruff_diagnostics::Diagnostic;
|
use ruff_linter::OldDiagnostic;
|
||||||
use ruff_linter::message::Message;
|
use ruff_linter::message::Message;
|
||||||
use ruff_linter::package::PackageRoot;
|
use ruff_linter::package::PackageRoot;
|
||||||
use ruff_linter::registry::Rule;
|
use ruff_linter::registry::Rule;
|
||||||
@@ -131,8 +131,7 @@ pub(crate) fn check(
|
|||||||
|
|
||||||
Diagnostics::new(
|
Diagnostics::new(
|
||||||
vec![Message::from_diagnostic(
|
vec![Message::from_diagnostic(
|
||||||
Diagnostic::new(IOError { message }, TextRange::default()),
|
OldDiagnostic::new(IOError { message }, TextRange::default(), &dummy),
|
||||||
dummy,
|
|
||||||
None,
|
None,
|
||||||
)],
|
)],
|
||||||
FxHashMap::default(),
|
FxHashMap::default(),
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ use serde::ser::SerializeSeq;
|
|||||||
use serde::{Serialize, Serializer};
|
use serde::{Serialize, Serializer};
|
||||||
use strum::IntoEnumIterator;
|
use strum::IntoEnumIterator;
|
||||||
|
|
||||||
use ruff_diagnostics::FixAvailability;
|
use ruff_linter::FixAvailability;
|
||||||
use ruff_linter::registry::{Linter, Rule, RuleNamespace};
|
use ruff_linter::registry::{Linter, Rule, RuleNamespace};
|
||||||
|
|
||||||
use crate::args::HelpFormat;
|
use crate::args::HelpFormat;
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ use colored::Colorize;
|
|||||||
use log::{debug, warn};
|
use log::{debug, warn};
|
||||||
use rustc_hash::FxHashMap;
|
use rustc_hash::FxHashMap;
|
||||||
|
|
||||||
use ruff_diagnostics::Diagnostic;
|
use ruff_linter::OldDiagnostic;
|
||||||
use ruff_linter::codes::Rule;
|
use ruff_linter::codes::Rule;
|
||||||
use ruff_linter::linter::{FixTable, FixerResult, LinterResult, ParseSource, lint_fix, lint_only};
|
use ruff_linter::linter::{FixTable, FixerResult, LinterResult, ParseSource, lint_fix, lint_only};
|
||||||
use ruff_linter::message::Message;
|
use ruff_linter::message::Message;
|
||||||
@@ -64,13 +64,13 @@ impl Diagnostics {
|
|||||||
let source_file = SourceFileBuilder::new(name, "").finish();
|
let source_file = SourceFileBuilder::new(name, "").finish();
|
||||||
Self::new(
|
Self::new(
|
||||||
vec![Message::from_diagnostic(
|
vec![Message::from_diagnostic(
|
||||||
Diagnostic::new(
|
OldDiagnostic::new(
|
||||||
IOError {
|
IOError {
|
||||||
message: err.to_string(),
|
message: err.to_string(),
|
||||||
},
|
},
|
||||||
TextRange::default(),
|
TextRange::default(),
|
||||||
|
&source_file,
|
||||||
),
|
),
|
||||||
source_file,
|
|
||||||
None,
|
None,
|
||||||
)],
|
)],
|
||||||
FxHashMap::default(),
|
FxHashMap::default(),
|
||||||
@@ -235,7 +235,7 @@ pub(crate) fn lint_path(
|
|||||||
};
|
};
|
||||||
let source_file =
|
let source_file =
|
||||||
SourceFileBuilder::new(path.to_string_lossy(), contents).finish();
|
SourceFileBuilder::new(path.to_string_lossy(), contents).finish();
|
||||||
lint_pyproject_toml(source_file, settings)
|
lint_pyproject_toml(&source_file, settings)
|
||||||
} else {
|
} else {
|
||||||
vec![]
|
vec![]
|
||||||
};
|
};
|
||||||
@@ -396,7 +396,7 @@ pub(crate) fn lint_stdin(
|
|||||||
}
|
}
|
||||||
|
|
||||||
return Ok(Diagnostics {
|
return Ok(Diagnostics {
|
||||||
messages: lint_pyproject_toml(source_file, &settings.linter),
|
messages: lint_pyproject_toml(&source_file, &settings.linter),
|
||||||
fixed: FixMap::from_iter([(fs::relativize_path(path), FixTable::default())]),
|
fixed: FixMap::from_iter([(fs::relativize_path(path), FixTable::default())]),
|
||||||
notebook_indexes: FxHashMap::default(),
|
notebook_indexes: FxHashMap::default(),
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -566,7 +566,7 @@ fn venv() -> Result<()> {
|
|||||||
----- stderr -----
|
----- stderr -----
|
||||||
ruff failed
|
ruff failed
|
||||||
Cause: Invalid search path settings
|
Cause: Invalid search path settings
|
||||||
Cause: Failed to discover the site-packages directory: Invalid `--python` argument: `none` could not be canonicalized
|
Cause: Failed to discover the site-packages directory: Invalid `--python` argument: `none` does not point to a Python executable or a directory on disk
|
||||||
");
|
");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ fn setup_tomllib_case() -> Case {
|
|||||||
|
|
||||||
let src_root = SystemPath::new("/src");
|
let src_root = SystemPath::new("/src");
|
||||||
let mut metadata = ProjectMetadata::discover(src_root, &system).unwrap();
|
let mut metadata = ProjectMetadata::discover(src_root, &system).unwrap();
|
||||||
metadata.apply_cli_options(Options {
|
metadata.apply_options(Options {
|
||||||
environment: Some(EnvironmentOptions {
|
environment: Some(EnvironmentOptions {
|
||||||
python_version: Some(RangedValue::cli(PythonVersion::PY312)),
|
python_version: Some(RangedValue::cli(PythonVersion::PY312)),
|
||||||
..EnvironmentOptions::default()
|
..EnvironmentOptions::default()
|
||||||
@@ -131,7 +131,7 @@ fn benchmark_incremental(criterion: &mut Criterion) {
|
|||||||
fn setup() -> Case {
|
fn setup() -> Case {
|
||||||
let case = setup_tomllib_case();
|
let case = setup_tomllib_case();
|
||||||
|
|
||||||
let result: Vec<_> = case.db.check().unwrap();
|
let result: Vec<_> = case.db.check();
|
||||||
|
|
||||||
assert_diagnostics(&case.db, &result, EXPECTED_TOMLLIB_DIAGNOSTICS);
|
assert_diagnostics(&case.db, &result, EXPECTED_TOMLLIB_DIAGNOSTICS);
|
||||||
|
|
||||||
@@ -159,7 +159,7 @@ fn benchmark_incremental(criterion: &mut Criterion) {
|
|||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
|
|
||||||
let result = db.check().unwrap();
|
let result = db.check();
|
||||||
|
|
||||||
assert_eq!(result.len(), EXPECTED_TOMLLIB_DIAGNOSTICS.len());
|
assert_eq!(result.len(), EXPECTED_TOMLLIB_DIAGNOSTICS.len());
|
||||||
}
|
}
|
||||||
@@ -179,7 +179,7 @@ fn benchmark_cold(criterion: &mut Criterion) {
|
|||||||
setup_tomllib_case,
|
setup_tomllib_case,
|
||||||
|case| {
|
|case| {
|
||||||
let Case { db, .. } = case;
|
let Case { db, .. } = case;
|
||||||
let result: Vec<_> = db.check().unwrap();
|
let result: Vec<_> = db.check();
|
||||||
|
|
||||||
assert_diagnostics(db, &result, EXPECTED_TOMLLIB_DIAGNOSTICS);
|
assert_diagnostics(db, &result, EXPECTED_TOMLLIB_DIAGNOSTICS);
|
||||||
},
|
},
|
||||||
@@ -224,7 +224,7 @@ fn setup_micro_case(code: &str) -> Case {
|
|||||||
|
|
||||||
let src_root = SystemPath::new("/src");
|
let src_root = SystemPath::new("/src");
|
||||||
let mut metadata = ProjectMetadata::discover(src_root, &system).unwrap();
|
let mut metadata = ProjectMetadata::discover(src_root, &system).unwrap();
|
||||||
metadata.apply_cli_options(Options {
|
metadata.apply_options(Options {
|
||||||
environment: Some(EnvironmentOptions {
|
environment: Some(EnvironmentOptions {
|
||||||
python_version: Some(RangedValue::cli(PythonVersion::PY312)),
|
python_version: Some(RangedValue::cli(PythonVersion::PY312)),
|
||||||
..EnvironmentOptions::default()
|
..EnvironmentOptions::default()
|
||||||
@@ -293,7 +293,7 @@ fn benchmark_many_string_assignments(criterion: &mut Criterion) {
|
|||||||
},
|
},
|
||||||
|case| {
|
|case| {
|
||||||
let Case { db, .. } = case;
|
let Case { db, .. } = case;
|
||||||
let result = db.check().unwrap();
|
let result = db.check();
|
||||||
assert_eq!(result.len(), 0);
|
assert_eq!(result.len(), 0);
|
||||||
},
|
},
|
||||||
BatchSize::SmallInput,
|
BatchSize::SmallInput,
|
||||||
@@ -339,7 +339,7 @@ fn benchmark_many_tuple_assignments(criterion: &mut Criterion) {
|
|||||||
},
|
},
|
||||||
|case| {
|
|case| {
|
||||||
let Case { db, .. } = case;
|
let Case { db, .. } = case;
|
||||||
let result = db.check().unwrap();
|
let result = db.check();
|
||||||
assert_eq!(result.len(), 0);
|
assert_eq!(result.len(), 0);
|
||||||
},
|
},
|
||||||
BatchSize::SmallInput,
|
BatchSize::SmallInput,
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
use std::any::Any;
|
||||||
use std::backtrace::BacktraceStatus;
|
use std::backtrace::BacktraceStatus;
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
use std::panic::Location;
|
use std::panic::Location;
|
||||||
@@ -24,17 +25,25 @@ impl Payload {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn downcast_ref<R: Any>(&self) -> Option<&R> {
|
||||||
|
self.0.downcast_ref::<R>()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Display for PanicError {
|
impl std::fmt::Display for PanicError {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
writeln!(f, "panicked at")?;
|
write!(f, "panicked at")?;
|
||||||
if let Some(location) = &self.location {
|
if let Some(location) = &self.location {
|
||||||
write!(f, " {location}")?;
|
write!(f, " {location}")?;
|
||||||
}
|
}
|
||||||
if let Some(payload) = self.payload.as_str() {
|
if let Some(payload) = self.payload.as_str() {
|
||||||
write!(f, ":\n{payload}")?;
|
write!(f, ":\n{payload}")?;
|
||||||
}
|
}
|
||||||
|
if let Some(query_trace) = self.salsa_backtrace.as_ref() {
|
||||||
|
let _ = writeln!(f, "{query_trace}");
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(backtrace) = &self.backtrace {
|
if let Some(backtrace) = &self.backtrace {
|
||||||
match backtrace.status() {
|
match backtrace.status() {
|
||||||
BacktraceStatus::Disabled => {
|
BacktraceStatus::Disabled => {
|
||||||
@@ -49,6 +58,7 @@ impl std::fmt::Display for PanicError {
|
|||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -596,6 +596,13 @@ impl AsRef<SystemPath> for Utf8PathBuf {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl AsRef<SystemPath> for camino::Utf8Component<'_> {
|
||||||
|
#[inline]
|
||||||
|
fn as_ref(&self) -> &SystemPath {
|
||||||
|
SystemPath::new(self.as_str())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl AsRef<SystemPath> for str {
|
impl AsRef<SystemPath> for str {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn as_ref(&self) -> &SystemPath {
|
fn as_ref(&self) -> &SystemPath {
|
||||||
@@ -626,6 +633,22 @@ impl Deref for SystemPathBuf {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<P: AsRef<SystemPath>> FromIterator<P> for SystemPathBuf {
|
||||||
|
fn from_iter<I: IntoIterator<Item = P>>(iter: I) -> Self {
|
||||||
|
let mut buf = SystemPathBuf::new();
|
||||||
|
buf.extend(iter);
|
||||||
|
buf
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<P: AsRef<SystemPath>> Extend<P> for SystemPathBuf {
|
||||||
|
fn extend<I: IntoIterator<Item = P>>(&mut self, iter: I) {
|
||||||
|
for path in iter {
|
||||||
|
self.push(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl std::fmt::Debug for SystemPath {
|
impl std::fmt::Debug for SystemPath {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
self.0.fmt(f)
|
self.0.fmt(f)
|
||||||
|
|||||||
@@ -13,12 +13,12 @@ pub fn assert_function_query_was_not_run<Db, Q, QDb, I, R>(
|
|||||||
Q: Fn(QDb, I) -> R,
|
Q: Fn(QDb, I) -> R,
|
||||||
I: salsa::plumbing::AsId + std::fmt::Debug + Copy,
|
I: salsa::plumbing::AsId + std::fmt::Debug + Copy,
|
||||||
{
|
{
|
||||||
let id = input.as_id().as_u32();
|
let id = input.as_id();
|
||||||
let (query_name, will_execute_event) = find_will_execute_event(db, query, input, events);
|
let (query_name, will_execute_event) = find_will_execute_event(db, query, input, events);
|
||||||
|
|
||||||
db.attach(|_| {
|
db.attach(|_| {
|
||||||
if let Some(will_execute_event) = will_execute_event {
|
if let Some(will_execute_event) = will_execute_event {
|
||||||
panic!("Expected query {query_name}({id}) not to have run but it did: {will_execute_event:?}\n\n{events:#?}");
|
panic!("Expected query {query_name}({id:?}) not to have run but it did: {will_execute_event:?}\n\n{events:#?}");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -65,7 +65,7 @@ pub fn assert_function_query_was_run<Db, Q, QDb, I, R>(
|
|||||||
Q: Fn(QDb, I) -> R,
|
Q: Fn(QDb, I) -> R,
|
||||||
I: salsa::plumbing::AsId + std::fmt::Debug + Copy,
|
I: salsa::plumbing::AsId + std::fmt::Debug + Copy,
|
||||||
{
|
{
|
||||||
let id = input.as_id().as_u32();
|
let id = input.as_id();
|
||||||
let (query_name, will_execute_event) = find_will_execute_event(db, query, input, events);
|
let (query_name, will_execute_event) = find_will_execute_event(db, query, input, events);
|
||||||
|
|
||||||
db.attach(|_| {
|
db.attach(|_| {
|
||||||
@@ -224,7 +224,7 @@ fn query_was_not_run() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[should_panic(expected = "Expected query len(0) not to have run but it did:")]
|
#[should_panic(expected = "Expected query len(Id(0)) not to have run but it did:")]
|
||||||
fn query_was_not_run_fails_if_query_was_run() {
|
fn query_was_not_run_fails_if_query_was_run() {
|
||||||
use crate::tests::TestDb;
|
use crate::tests::TestDb;
|
||||||
use salsa::prelude::*;
|
use salsa::prelude::*;
|
||||||
@@ -287,7 +287,7 @@ fn const_query_was_not_run_fails_if_query_was_run() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[should_panic(expected = "Expected query len(0) to have run but it did not:")]
|
#[should_panic(expected = "Expected query len(Id(0)) to have run but it did not:")]
|
||||||
fn query_was_run_fails_if_query_was_not_run() {
|
fn query_was_run_fails_if_query_was_not_run() {
|
||||||
use crate::tests::TestDb;
|
use crate::tests::TestDb;
|
||||||
use salsa::prelude::*;
|
use salsa::prelude::*;
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ license = { workspace = true }
|
|||||||
ty = { workspace = true }
|
ty = { workspace = true }
|
||||||
ty_project = { workspace = true, features = ["schemars"] }
|
ty_project = { workspace = true, features = ["schemars"] }
|
||||||
ruff = { workspace = true }
|
ruff = { workspace = true }
|
||||||
ruff_diagnostics = { workspace = true }
|
|
||||||
ruff_formatter = { workspace = true }
|
ruff_formatter = { workspace = true }
|
||||||
ruff_linter = { workspace = true, features = ["schemars"] }
|
ruff_linter = { workspace = true, features = ["schemars"] }
|
||||||
ruff_notebook = { workspace = true }
|
ruff_notebook = { workspace = true }
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ use itertools::Itertools;
|
|||||||
use regex::{Captures, Regex};
|
use regex::{Captures, Regex};
|
||||||
use strum::IntoEnumIterator;
|
use strum::IntoEnumIterator;
|
||||||
|
|
||||||
use ruff_diagnostics::FixAvailability;
|
use ruff_linter::FixAvailability;
|
||||||
use ruff_linter::registry::{Linter, Rule, RuleNamespace};
|
use ruff_linter::registry::{Linter, Rule, RuleNamespace};
|
||||||
use ruff_options_metadata::{OptionEntry, OptionsMetadata};
|
use ruff_options_metadata::{OptionEntry, OptionsMetadata};
|
||||||
use ruff_workspace::options::Options;
|
use ruff_workspace::options::Options;
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ use std::borrow::Cow;
|
|||||||
use std::fmt::Write;
|
use std::fmt::Write;
|
||||||
use strum::IntoEnumIterator;
|
use strum::IntoEnumIterator;
|
||||||
|
|
||||||
use ruff_diagnostics::FixAvailability;
|
use ruff_linter::FixAvailability;
|
||||||
use ruff_linter::registry::{Linter, Rule, RuleNamespace};
|
use ruff_linter::registry::{Linter, Rule, RuleNamespace};
|
||||||
use ruff_linter::upstream_categories::UpstreamCategoryAndPrefix;
|
use ruff_linter::upstream_categories::UpstreamCategoryAndPrefix;
|
||||||
use ruff_options_metadata::OptionsMetadata;
|
use ruff_options_metadata::OptionsMetadata;
|
||||||
@@ -18,44 +18,43 @@ const FIX_SYMBOL: &str = "🛠️";
|
|||||||
const PREVIEW_SYMBOL: &str = "🧪";
|
const PREVIEW_SYMBOL: &str = "🧪";
|
||||||
const REMOVED_SYMBOL: &str = "❌";
|
const REMOVED_SYMBOL: &str = "❌";
|
||||||
const WARNING_SYMBOL: &str = "⚠️";
|
const WARNING_SYMBOL: &str = "⚠️";
|
||||||
const STABLE_SYMBOL: &str = "✔️";
|
|
||||||
const SPACER: &str = " ";
|
const SPACER: &str = " ";
|
||||||
|
|
||||||
|
/// Style for the rule's fixability and status icons.
|
||||||
|
const SYMBOL_STYLE: &str = "style='width: 1em; display: inline-block;'";
|
||||||
|
/// Style for the container wrapping the fixability and status icons.
|
||||||
|
const SYMBOLS_CONTAINER: &str = "style='display: flex; gap: 0.5rem; justify-content: end;'";
|
||||||
|
|
||||||
fn generate_table(table_out: &mut String, rules: impl IntoIterator<Item = Rule>, linter: &Linter) {
|
fn generate_table(table_out: &mut String, rules: impl IntoIterator<Item = Rule>, linter: &Linter) {
|
||||||
table_out.push_str("| Code | Name | Message | |");
|
table_out.push_str("| Code | Name | Message | |");
|
||||||
table_out.push('\n');
|
table_out.push('\n');
|
||||||
table_out.push_str("| ---- | ---- | ------- | ------: |");
|
table_out.push_str("| ---- | ---- | ------- | -: |");
|
||||||
table_out.push('\n');
|
table_out.push('\n');
|
||||||
for rule in rules {
|
for rule in rules {
|
||||||
let status_token = match rule.group() {
|
let status_token = match rule.group() {
|
||||||
RuleGroup::Removed => {
|
RuleGroup::Removed => {
|
||||||
format!("<span title='Rule has been removed'>{REMOVED_SYMBOL}</span>")
|
format!(
|
||||||
|
"<span {SYMBOL_STYLE} title='Rule has been removed'>{REMOVED_SYMBOL}</span>"
|
||||||
|
)
|
||||||
}
|
}
|
||||||
RuleGroup::Deprecated => {
|
RuleGroup::Deprecated => {
|
||||||
format!("<span title='Rule has been deprecated'>{WARNING_SYMBOL}</span>")
|
format!(
|
||||||
|
"<span {SYMBOL_STYLE} title='Rule has been deprecated'>{WARNING_SYMBOL}</span>"
|
||||||
|
)
|
||||||
}
|
}
|
||||||
RuleGroup::Preview => {
|
RuleGroup::Preview => {
|
||||||
format!("<span title='Rule is in preview'>{PREVIEW_SYMBOL}</span>")
|
format!("<span {SYMBOL_STYLE} title='Rule is in preview'>{PREVIEW_SYMBOL}</span>")
|
||||||
}
|
|
||||||
RuleGroup::Stable => {
|
|
||||||
// A full opacity checkmark is a bit aggressive for indicating stable
|
|
||||||
format!("<span title='Rule is stable' style='opacity: 0.6'>{STABLE_SYMBOL}</span>")
|
|
||||||
}
|
}
|
||||||
|
RuleGroup::Stable => format!("<span {SYMBOL_STYLE}></span>"),
|
||||||
};
|
};
|
||||||
|
|
||||||
let fix_token = match rule.fixable() {
|
let fix_token = match rule.fixable() {
|
||||||
FixAvailability::Always | FixAvailability::Sometimes => {
|
FixAvailability::Always | FixAvailability::Sometimes => {
|
||||||
format!("<span title='Automatic fix available'>{FIX_SYMBOL}</span>")
|
format!("<span {SYMBOL_STYLE} title='Automatic fix available'>{FIX_SYMBOL}</span>")
|
||||||
}
|
|
||||||
FixAvailability::None => {
|
|
||||||
format!(
|
|
||||||
"<span title='Automatic fix not available' style='opacity: 0.1' aria-hidden='true'>{FIX_SYMBOL}</span>"
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
FixAvailability::None => format!("<span {SYMBOL_STYLE}></span>"),
|
||||||
};
|
};
|
||||||
|
|
||||||
let tokens = format!("{status_token} {fix_token}");
|
|
||||||
|
|
||||||
let rule_name = rule.as_ref();
|
let rule_name = rule.as_ref();
|
||||||
|
|
||||||
// If the message ends in a bracketed expression (like: "Use {replacement}"), escape the
|
// If the message ends in a bracketed expression (like: "Use {replacement}"), escape the
|
||||||
@@ -82,15 +81,14 @@ fn generate_table(table_out: &mut String, rules: impl IntoIterator<Item = Rule>,
|
|||||||
#[expect(clippy::or_fun_call)]
|
#[expect(clippy::or_fun_call)]
|
||||||
let _ = write!(
|
let _ = write!(
|
||||||
table_out,
|
table_out,
|
||||||
"| {ss}{0}{1}{se} {{ #{0}{1} }} | {ss}{2}{se} | {ss}{3}{se} | {ss}{4}{se} |",
|
"| {ss}{prefix}{code}{se} {{ #{prefix}{code} }} | {ss}{explanation}{se} | {ss}{message}{se} | <div {SYMBOLS_CONTAINER}>{status_token}{fix_token}</div>|",
|
||||||
linter.common_prefix(),
|
prefix = linter.common_prefix(),
|
||||||
linter.code_for_rule(rule).unwrap(),
|
code = linter.code_for_rule(rule).unwrap(),
|
||||||
rule.explanation()
|
explanation = rule
|
||||||
|
.explanation()
|
||||||
.is_some()
|
.is_some()
|
||||||
.then_some(format_args!("[{rule_name}](rules/{rule_name}.md)"))
|
.then_some(format_args!("[{rule_name}](rules/{rule_name}.md)"))
|
||||||
.unwrap_or(format_args!("{rule_name}")),
|
.unwrap_or(format_args!("{rule_name}")),
|
||||||
message,
|
|
||||||
tokens,
|
|
||||||
);
|
);
|
||||||
table_out.push('\n');
|
table_out.push('\n');
|
||||||
}
|
}
|
||||||
@@ -104,12 +102,6 @@ pub(crate) fn generate() -> String {
|
|||||||
table_out.push_str("### Legend");
|
table_out.push_str("### Legend");
|
||||||
table_out.push('\n');
|
table_out.push('\n');
|
||||||
|
|
||||||
let _ = write!(
|
|
||||||
&mut table_out,
|
|
||||||
"{SPACER}{STABLE_SYMBOL}{SPACER} The rule is stable."
|
|
||||||
);
|
|
||||||
table_out.push_str("<br />");
|
|
||||||
|
|
||||||
let _ = write!(
|
let _ = write!(
|
||||||
&mut table_out,
|
&mut table_out,
|
||||||
"{SPACER}{PREVIEW_SYMBOL}{SPACER} The rule is unstable and is in [\"preview\"](faq.md#what-is-preview)."
|
"{SPACER}{PREVIEW_SYMBOL}{SPACER} The rule is unstable and is in [\"preview\"](faq.md#what-is-preview)."
|
||||||
@@ -132,7 +124,8 @@ pub(crate) fn generate() -> String {
|
|||||||
&mut table_out,
|
&mut table_out,
|
||||||
"{SPACER}{FIX_SYMBOL}{SPACER} The rule is automatically fixable by the `--fix` command-line option."
|
"{SPACER}{FIX_SYMBOL}{SPACER} The rule is automatically fixable by the `--fix` command-line option."
|
||||||
);
|
);
|
||||||
table_out.push_str("<br />");
|
table_out.push_str("\n\n");
|
||||||
|
table_out.push_str("All rules not marked as preview, deprecated or removed are stable.");
|
||||||
table_out.push('\n');
|
table_out.push('\n');
|
||||||
|
|
||||||
for linter in Linter::iter() {
|
for linter in Linter::iter() {
|
||||||
|
|||||||
@@ -16,7 +16,5 @@ doctest = false
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
ruff_text_size = { workspace = true }
|
ruff_text_size = { workspace = true }
|
||||||
|
|
||||||
anyhow = { workspace = true }
|
|
||||||
log = { workspace = true }
|
|
||||||
is-macro = { workspace = true }
|
is-macro = { workspace = true }
|
||||||
serde = { workspace = true, optional = true, features = [] }
|
serde = { workspace = true, optional = true, features = [] }
|
||||||
|
|||||||
@@ -1,11 +1,7 @@
|
|||||||
pub use diagnostic::Diagnostic;
|
|
||||||
pub use edit::Edit;
|
pub use edit::Edit;
|
||||||
pub use fix::{Applicability, Fix, IsolationLevel};
|
pub use fix::{Applicability, Fix, IsolationLevel};
|
||||||
pub use source_map::{SourceMap, SourceMarker};
|
pub use source_map::{SourceMap, SourceMarker};
|
||||||
pub use violation::{AlwaysFixableViolation, FixAvailability, Violation, ViolationMetadata};
|
|
||||||
|
|
||||||
mod diagnostic;
|
|
||||||
mod edit;
|
mod edit;
|
||||||
mod fix;
|
mod fix;
|
||||||
mod source_map;
|
mod source_map;
|
||||||
mod violation;
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ use ruff_python_ast::PythonVersion;
|
|||||||
use ty_python_semantic::lint::{LintRegistry, RuleSelection};
|
use ty_python_semantic::lint::{LintRegistry, RuleSelection};
|
||||||
use ty_python_semantic::{
|
use ty_python_semantic::{
|
||||||
Db, Program, ProgramSettings, PythonPath, PythonPlatform, PythonVersionSource,
|
Db, Program, ProgramSettings, PythonPath, PythonPlatform, PythonVersionSource,
|
||||||
PythonVersionWithSource, SearchPathSettings, default_lint_registry,
|
PythonVersionWithSource, SearchPathSettings, SysPrefixPathOrigin, default_lint_registry,
|
||||||
};
|
};
|
||||||
|
|
||||||
static EMPTY_VENDORED: std::sync::LazyLock<VendoredFileSystem> = std::sync::LazyLock::new(|| {
|
static EMPTY_VENDORED: std::sync::LazyLock<VendoredFileSystem> = std::sync::LazyLock::new(|| {
|
||||||
@@ -37,17 +37,18 @@ impl ModuleDb {
|
|||||||
) -> Result<Self> {
|
) -> Result<Self> {
|
||||||
let mut search_paths = SearchPathSettings::new(src_roots);
|
let mut search_paths = SearchPathSettings::new(src_roots);
|
||||||
if let Some(venv_path) = venv_path {
|
if let Some(venv_path) = venv_path {
|
||||||
search_paths.python_path = PythonPath::from_cli_flag(venv_path);
|
search_paths.python_path =
|
||||||
|
PythonPath::sys_prefix(venv_path, SysPrefixPathOrigin::PythonCliFlag);
|
||||||
}
|
}
|
||||||
|
|
||||||
let db = Self::default();
|
let db = Self::default();
|
||||||
Program::from_settings(
|
Program::from_settings(
|
||||||
&db,
|
&db,
|
||||||
ProgramSettings {
|
ProgramSettings {
|
||||||
python_version: PythonVersionWithSource {
|
python_version: Some(PythonVersionWithSource {
|
||||||
version: python_version,
|
version: python_version,
|
||||||
source: PythonVersionSource::default(),
|
source: PythonVersionSource::default(),
|
||||||
},
|
}),
|
||||||
python_platform: PythonPlatform::default(),
|
python_platform: PythonPlatform::default(),
|
||||||
search_paths,
|
search_paths,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "ruff_linter"
|
name = "ruff_linter"
|
||||||
version = "0.11.11"
|
version = "0.11.12"
|
||||||
publish = false
|
publish = false
|
||||||
authors = { workspace = true }
|
authors = { workspace = true }
|
||||||
edition = { workspace = true }
|
edition = { workspace = true }
|
||||||
|
|||||||
@@ -10,22 +10,10 @@ from airflow import (
|
|||||||
PY312,
|
PY312,
|
||||||
)
|
)
|
||||||
from airflow.api_connexion.security import requires_access
|
from airflow.api_connexion.security import requires_access
|
||||||
from airflow.configuration import (
|
|
||||||
as_dict,
|
|
||||||
get,
|
|
||||||
getboolean,
|
|
||||||
getfloat,
|
|
||||||
getint,
|
|
||||||
has_option,
|
|
||||||
remove_option,
|
|
||||||
set,
|
|
||||||
)
|
|
||||||
from airflow.contrib.aws_athena_hook import AWSAthenaHook
|
from airflow.contrib.aws_athena_hook import AWSAthenaHook
|
||||||
from airflow.datasets import DatasetAliasEvent
|
from airflow.datasets import DatasetAliasEvent
|
||||||
from airflow.hooks.base_hook import BaseHook
|
|
||||||
from airflow.operators.subdag import SubDagOperator
|
from airflow.operators.subdag import SubDagOperator
|
||||||
from airflow.secrets.local_filesystem import LocalFilesystemBackend
|
from airflow.secrets.local_filesystem import LocalFilesystemBackend
|
||||||
from airflow.sensors.base_sensor_operator import BaseSensorOperator
|
|
||||||
from airflow.triggers.external_task import TaskStateTrigger
|
from airflow.triggers.external_task import TaskStateTrigger
|
||||||
from airflow.utils import dates
|
from airflow.utils import dates
|
||||||
from airflow.utils.dag_cycle_tester import test_cycle
|
from airflow.utils.dag_cycle_tester import test_cycle
|
||||||
@@ -40,13 +28,10 @@ from airflow.utils.dates import (
|
|||||||
)
|
)
|
||||||
from airflow.utils.db import create_session
|
from airflow.utils.db import create_session
|
||||||
from airflow.utils.decorators import apply_defaults
|
from airflow.utils.decorators import apply_defaults
|
||||||
from airflow.utils.file import TemporaryDirectory, mkdirs
|
from airflow.utils.file import mkdirs
|
||||||
from airflow.utils.helpers import chain as helper_chain
|
|
||||||
from airflow.utils.helpers import cross_downstream as helper_cross_downstream
|
|
||||||
from airflow.utils.log import secrets_masker
|
|
||||||
from airflow.utils.state import SHUTDOWN, terminating_states
|
from airflow.utils.state import SHUTDOWN, terminating_states
|
||||||
from airflow.utils.trigger_rule import TriggerRule
|
from airflow.utils.trigger_rule import TriggerRule
|
||||||
from airflow.www.auth import has_access
|
from airflow.www.auth import has_access, has_access_dataset
|
||||||
from airflow.www.utils import get_sensitive_variables_fields, should_hide_value_for_key
|
from airflow.www.utils import get_sensitive_variables_fields, should_hide_value_for_key
|
||||||
|
|
||||||
# airflow root
|
# airflow root
|
||||||
@@ -55,11 +40,6 @@ PY36, PY37, PY38, PY39, PY310, PY311, PY312
|
|||||||
# airflow.api_connexion.security
|
# airflow.api_connexion.security
|
||||||
requires_access
|
requires_access
|
||||||
|
|
||||||
|
|
||||||
# airflow.configuration
|
|
||||||
get, getboolean, getfloat, getint, has_option, remove_option, as_dict, set
|
|
||||||
|
|
||||||
|
|
||||||
# airflow.contrib.*
|
# airflow.contrib.*
|
||||||
AWSAthenaHook()
|
AWSAthenaHook()
|
||||||
|
|
||||||
@@ -68,10 +48,6 @@ AWSAthenaHook()
|
|||||||
DatasetAliasEvent()
|
DatasetAliasEvent()
|
||||||
|
|
||||||
|
|
||||||
# airflow.hooks
|
|
||||||
BaseHook()
|
|
||||||
|
|
||||||
|
|
||||||
# airflow.operators.subdag.*
|
# airflow.operators.subdag.*
|
||||||
SubDagOperator()
|
SubDagOperator()
|
||||||
|
|
||||||
@@ -81,10 +57,6 @@ SubDagOperator()
|
|||||||
LocalFilesystemBackend()
|
LocalFilesystemBackend()
|
||||||
|
|
||||||
|
|
||||||
# airflow.sensors.base_sensor_operator
|
|
||||||
BaseSensorOperator()
|
|
||||||
|
|
||||||
|
|
||||||
# airflow.triggers.external_task
|
# airflow.triggers.external_task
|
||||||
TaskStateTrigger()
|
TaskStateTrigger()
|
||||||
|
|
||||||
@@ -114,15 +86,8 @@ create_session
|
|||||||
apply_defaults
|
apply_defaults
|
||||||
|
|
||||||
# airflow.utils.file
|
# airflow.utils.file
|
||||||
TemporaryDirectory()
|
|
||||||
mkdirs
|
mkdirs
|
||||||
|
|
||||||
# airflow.utils.helpers
|
|
||||||
helper_chain
|
|
||||||
helper_cross_downstream
|
|
||||||
|
|
||||||
# airflow.utils.log
|
|
||||||
secrets_masker
|
|
||||||
|
|
||||||
# airflow.utils.state
|
# airflow.utils.state
|
||||||
SHUTDOWN
|
SHUTDOWN
|
||||||
@@ -135,37 +100,8 @@ TriggerRule.NONE_FAILED_OR_SKIPPED
|
|||||||
|
|
||||||
# airflow.www.auth
|
# airflow.www.auth
|
||||||
has_access
|
has_access
|
||||||
|
has_access_dataset
|
||||||
|
|
||||||
# airflow.www.utils
|
# airflow.www.utils
|
||||||
get_sensitive_variables_fields
|
get_sensitive_variables_fields
|
||||||
should_hide_value_for_key
|
should_hide_value_for_key
|
||||||
|
|
||||||
# airflow.operators.python
|
|
||||||
from airflow.operators.python import get_current_context
|
|
||||||
|
|
||||||
get_current_context()
|
|
||||||
|
|
||||||
# airflow.providers.mysql
|
|
||||||
from airflow.providers.mysql.datasets.mysql import sanitize_uri
|
|
||||||
|
|
||||||
sanitize_uri
|
|
||||||
|
|
||||||
# airflow.providers.postgres
|
|
||||||
from airflow.providers.postgres.datasets.postgres import sanitize_uri
|
|
||||||
|
|
||||||
sanitize_uri
|
|
||||||
|
|
||||||
# airflow.providers.trino
|
|
||||||
from airflow.providers.trino.datasets.trino import sanitize_uri
|
|
||||||
|
|
||||||
sanitize_uri
|
|
||||||
|
|
||||||
# airflow.notifications.basenotifier
|
|
||||||
from airflow.notifications.basenotifier import BaseNotifier
|
|
||||||
|
|
||||||
BaseNotifier()
|
|
||||||
|
|
||||||
# airflow.auth.manager
|
|
||||||
from airflow.auth.managers.base_auth_manager import BaseAuthManager
|
|
||||||
|
|
||||||
BaseAuthManager()
|
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ from __future__ import annotations
|
|||||||
from airflow.api_connexion.security import requires_access_dataset
|
from airflow.api_connexion.security import requires_access_dataset
|
||||||
from airflow.auth.managers.models.resource_details import (
|
from airflow.auth.managers.models.resource_details import (
|
||||||
DatasetDetails,
|
DatasetDetails,
|
||||||
|
|
||||||
)
|
)
|
||||||
from airflow.datasets.manager import (
|
from airflow.datasets.manager import (
|
||||||
DatasetManager,
|
DatasetManager,
|
||||||
@@ -12,15 +11,13 @@ from airflow.datasets.manager import (
|
|||||||
)
|
)
|
||||||
from airflow.lineage.hook import DatasetLineageInfo
|
from airflow.lineage.hook import DatasetLineageInfo
|
||||||
from airflow.metrics.validators import AllowListValidator, BlockListValidator
|
from airflow.metrics.validators import AllowListValidator, BlockListValidator
|
||||||
from airflow.secrets.local_filesystm import load_connections
|
from airflow.secrets.local_filesystem import load_connections
|
||||||
from airflow.security.permissions import RESOURCE_DATASET
|
from airflow.security.permissions import RESOURCE_DATASET
|
||||||
from airflow.www.auth import has_access_dataset
|
|
||||||
|
|
||||||
requires_access_dataset()
|
requires_access_dataset()
|
||||||
|
|
||||||
DatasetDetails()
|
DatasetDetails()
|
||||||
|
|
||||||
|
|
||||||
DatasetManager()
|
DatasetManager()
|
||||||
dataset_manager()
|
dataset_manager()
|
||||||
resolve_dataset_manager()
|
resolve_dataset_manager()
|
||||||
@@ -34,7 +31,6 @@ load_connections()
|
|||||||
|
|
||||||
RESOURCE_DATASET
|
RESOURCE_DATASET
|
||||||
|
|
||||||
has_access_dataset()
|
|
||||||
|
|
||||||
from airflow.listeners.spec.dataset import (
|
from airflow.listeners.spec.dataset import (
|
||||||
on_dataset_changed,
|
on_dataset_changed,
|
||||||
@@ -43,3 +39,76 @@ from airflow.listeners.spec.dataset import (
|
|||||||
|
|
||||||
on_dataset_created()
|
on_dataset_created()
|
||||||
on_dataset_changed()
|
on_dataset_changed()
|
||||||
|
|
||||||
|
|
||||||
|
# airflow.operators.python
|
||||||
|
from airflow.operators.python import get_current_context
|
||||||
|
|
||||||
|
get_current_context()
|
||||||
|
|
||||||
|
# airflow.providers.mysql
|
||||||
|
from airflow.providers.mysql.datasets.mysql import sanitize_uri
|
||||||
|
|
||||||
|
sanitize_uri
|
||||||
|
|
||||||
|
# airflow.providers.postgres
|
||||||
|
from airflow.providers.postgres.datasets.postgres import sanitize_uri
|
||||||
|
|
||||||
|
sanitize_uri
|
||||||
|
|
||||||
|
# airflow.providers.trino
|
||||||
|
from airflow.providers.trino.datasets.trino import sanitize_uri
|
||||||
|
|
||||||
|
sanitize_uri
|
||||||
|
|
||||||
|
# airflow.notifications.basenotifier
|
||||||
|
from airflow.notifications.basenotifier import BaseNotifier
|
||||||
|
|
||||||
|
BaseNotifier()
|
||||||
|
|
||||||
|
# airflow.auth.manager
|
||||||
|
from airflow.auth.managers.base_auth_manager import BaseAuthManager
|
||||||
|
|
||||||
|
BaseAuthManager()
|
||||||
|
|
||||||
|
|
||||||
|
from airflow.configuration import (
|
||||||
|
as_dict,
|
||||||
|
get,
|
||||||
|
getboolean,
|
||||||
|
getfloat,
|
||||||
|
getint,
|
||||||
|
has_option,
|
||||||
|
remove_option,
|
||||||
|
set,
|
||||||
|
)
|
||||||
|
|
||||||
|
# airflow.configuration
|
||||||
|
get, getboolean, getfloat, getint, has_option, remove_option, as_dict, set
|
||||||
|
from airflow.hooks.base_hook import BaseHook
|
||||||
|
|
||||||
|
# airflow.hooks
|
||||||
|
BaseHook()
|
||||||
|
|
||||||
|
from airflow.sensors.base_sensor_operator import BaseSensorOperator
|
||||||
|
|
||||||
|
# airflow.sensors.base_sensor_operator
|
||||||
|
BaseSensorOperator()
|
||||||
|
BaseHook()
|
||||||
|
|
||||||
|
from airflow.utils.helpers import chain as helper_chain
|
||||||
|
from airflow.utils.helpers import cross_downstream as helper_cross_downstream
|
||||||
|
|
||||||
|
# airflow.utils.helpers
|
||||||
|
helper_chain
|
||||||
|
helper_cross_downstream
|
||||||
|
|
||||||
|
# airflow.utils.file
|
||||||
|
from airflow.utils.file import TemporaryDirectory
|
||||||
|
|
||||||
|
TemporaryDirectory()
|
||||||
|
|
||||||
|
from airflow.utils.log import secrets_masker
|
||||||
|
|
||||||
|
# airflow.utils.log
|
||||||
|
secrets_masker
|
||||||
|
|||||||
@@ -1,54 +1,54 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from airflow.providers.amazon.aws.auth_manager.avp.entities import AvpEntities
|
from airflow.providers.amazon.aws.auth_manager.avp.entities import AvpEntities
|
||||||
|
from airflow.providers.openlineage.utils.utils import (
|
||||||
|
DatasetInfo,
|
||||||
|
translate_airflow_dataset,
|
||||||
|
)
|
||||||
|
from airflow.secrets.local_filesystem import load_connections
|
||||||
|
from airflow.security.permissions import RESOURCE_DATASET
|
||||||
|
|
||||||
|
AvpEntities.DATASET
|
||||||
|
|
||||||
|
# airflow.providers.openlineage.utils.utils
|
||||||
|
DatasetInfo()
|
||||||
|
translate_airflow_dataset()
|
||||||
|
|
||||||
|
# airflow.secrets.local_filesystem
|
||||||
|
load_connections()
|
||||||
|
|
||||||
|
# airflow.security.permissions
|
||||||
|
RESOURCE_DATASET
|
||||||
|
|
||||||
from airflow.providers.amazon.aws.datasets.s3 import (
|
from airflow.providers.amazon.aws.datasets.s3 import (
|
||||||
convert_dataset_to_openlineage as s3_convert_dataset_to_openlineage,
|
convert_dataset_to_openlineage as s3_convert_dataset_to_openlineage,
|
||||||
)
|
)
|
||||||
from airflow.providers.amazon.aws.datasets.s3 import create_dataset as s3_create_dataset
|
from airflow.providers.amazon.aws.datasets.s3 import create_dataset as s3_create_dataset
|
||||||
|
|
||||||
|
s3_create_dataset()
|
||||||
|
s3_convert_dataset_to_openlineage()
|
||||||
|
|
||||||
from airflow.providers.common.io.dataset.file import (
|
from airflow.providers.common.io.dataset.file import (
|
||||||
convert_dataset_to_openlineage as io_convert_dataset_to_openlineage,
|
convert_dataset_to_openlineage as io_convert_dataset_to_openlineage,
|
||||||
)
|
)
|
||||||
from airflow.providers.common.io.dataset.file import create_dataset as io_create_dataset
|
from airflow.providers.common.io.dataset.file import create_dataset as io_create_dataset
|
||||||
|
|
||||||
from airflow.providers.google.datasets.bigquery import (
|
|
||||||
create_dataset as bigquery_create_dataset,
|
|
||||||
)
|
|
||||||
from airflow.providers.google.datasets.gcs import (
|
|
||||||
convert_dataset_to_openlineage as gcs_convert_dataset_to_openlineage,
|
|
||||||
)
|
|
||||||
from airflow.providers.google.datasets.gcs import create_dataset as gcs_create_dataset
|
|
||||||
from airflow.providers.openlineage.utils.utils import (
|
|
||||||
DatasetInfo,
|
|
||||||
translate_airflow_dataset,
|
|
||||||
)
|
|
||||||
|
|
||||||
AvpEntities.DATASET
|
|
||||||
|
|
||||||
s3_create_dataset()
|
|
||||||
s3_convert_dataset_to_openlineage()
|
|
||||||
|
|
||||||
io_create_dataset()
|
io_create_dataset()
|
||||||
io_convert_dataset_to_openlineage()
|
io_convert_dataset_to_openlineage()
|
||||||
|
|
||||||
|
|
||||||
|
# # airflow.providers.google.datasets.bigquery
|
||||||
|
from airflow.providers.google.datasets.bigquery import (
|
||||||
|
create_dataset as bigquery_create_dataset,
|
||||||
|
)
|
||||||
|
|
||||||
# airflow.providers.google.datasets.bigquery
|
|
||||||
bigquery_create_dataset()
|
bigquery_create_dataset()
|
||||||
|
|
||||||
# airflow.providers.google.datasets.gcs
|
# airflow.providers.google.datasets.gcs
|
||||||
|
from airflow.providers.google.datasets.gcs import (
|
||||||
|
convert_dataset_to_openlineage as gcs_convert_dataset_to_openlineage,
|
||||||
|
)
|
||||||
|
from airflow.providers.google.datasets.gcs import create_dataset as gcs_create_dataset
|
||||||
|
|
||||||
gcs_create_dataset()
|
gcs_create_dataset()
|
||||||
gcs_convert_dataset_to_openlineage()
|
gcs_convert_dataset_to_openlineage()
|
||||||
# airflow.providers.openlineage.utils.utils
|
|
||||||
DatasetInfo()
|
|
||||||
translate_airflow_dataset()
|
|
||||||
#
|
|
||||||
# airflow.secrets.local_filesystem
|
|
||||||
load_connections()
|
|
||||||
#
|
|
||||||
# airflow.security.permissions
|
|
||||||
RESOURCE_DATASET
|
|
||||||
|
|
||||||
# airflow.timetables
|
|
||||||
DatasetTriggeredTimetable()
|
|
||||||
#
|
|
||||||
# airflow.www.auth
|
|
||||||
has_access_dataset
|
|
||||||
|
|||||||
@@ -5,35 +5,30 @@ from airflow.hooks.S3_hook import (
|
|||||||
provide_bucket_name,
|
provide_bucket_name,
|
||||||
)
|
)
|
||||||
from airflow.operators.gcs_to_s3 import GCSToS3Operator
|
from airflow.operators.gcs_to_s3 import GCSToS3Operator
|
||||||
from airflow.operators.google_api_to_s3_transfer import (
|
from airflow.operators.google_api_to_s3_transfer import GoogleApiToS3Operator
|
||||||
GoogleApiToS3Operator,
|
from airflow.operators.redshift_to_s3_operator import RedshiftToS3Operator
|
||||||
GoogleApiToS3Transfer,
|
|
||||||
)
|
|
||||||
from airflow.operators.redshift_to_s3_operator import (
|
|
||||||
RedshiftToS3Operator,
|
|
||||||
RedshiftToS3Transfer,
|
|
||||||
)
|
|
||||||
from airflow.operators.s3_file_transform_operator import S3FileTransformOperator
|
from airflow.operators.s3_file_transform_operator import S3FileTransformOperator
|
||||||
from airflow.operators.s3_to_redshift_operator import (
|
from airflow.operators.s3_to_redshift_operator import S3ToRedshiftOperator
|
||||||
S3ToRedshiftOperator,
|
|
||||||
S3ToRedshiftTransfer,
|
|
||||||
)
|
|
||||||
from airflow.sensors.s3_key_sensor import S3KeySensor
|
from airflow.sensors.s3_key_sensor import S3KeySensor
|
||||||
|
|
||||||
S3Hook()
|
S3Hook()
|
||||||
provide_bucket_name()
|
provide_bucket_name()
|
||||||
|
|
||||||
GCSToS3Operator()
|
GCSToS3Operator()
|
||||||
|
|
||||||
GoogleApiToS3Operator()
|
GoogleApiToS3Operator()
|
||||||
|
RedshiftToS3Operator()
|
||||||
|
S3FileTransformOperator()
|
||||||
|
S3ToRedshiftOperator()
|
||||||
|
S3KeySensor()
|
||||||
|
|
||||||
|
from airflow.operators.google_api_to_s3_transfer import GoogleApiToS3Transfer
|
||||||
|
|
||||||
GoogleApiToS3Transfer()
|
GoogleApiToS3Transfer()
|
||||||
|
|
||||||
RedshiftToS3Operator()
|
from airflow.operators.redshift_to_s3_operator import RedshiftToS3Transfer
|
||||||
|
|
||||||
RedshiftToS3Transfer()
|
RedshiftToS3Transfer()
|
||||||
|
|
||||||
S3FileTransformOperator()
|
from airflow.operators.s3_to_redshift_operator import S3ToRedshiftTransfer
|
||||||
|
|
||||||
S3ToRedshiftOperator()
|
|
||||||
S3ToRedshiftTransfer()
|
S3ToRedshiftTransfer()
|
||||||
|
|
||||||
S3KeySensor()
|
|
||||||
|
|||||||
@@ -4,10 +4,13 @@ from airflow.hooks.dbapi import (
|
|||||||
ConnectorProtocol,
|
ConnectorProtocol,
|
||||||
DbApiHook,
|
DbApiHook,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
ConnectorProtocol()
|
||||||
|
DbApiHook()
|
||||||
|
|
||||||
from airflow.hooks.dbapi_hook import DbApiHook
|
from airflow.hooks.dbapi_hook import DbApiHook
|
||||||
from airflow.operators.check_operator import SQLCheckOperator
|
from airflow.operators.check_operator import SQLCheckOperator
|
||||||
|
|
||||||
ConnectorProtocol()
|
|
||||||
DbApiHook()
|
DbApiHook()
|
||||||
SQLCheckOperator()
|
SQLCheckOperator()
|
||||||
|
|
||||||
@@ -114,16 +117,11 @@ from airflow.sensors.sql_sensor import SqlSensor
|
|||||||
SqlSensor()
|
SqlSensor()
|
||||||
|
|
||||||
|
|
||||||
from airflow.operators.jdbc_operator import JdbcOperator
|
from airflow.providers.common.sql.operators.sql import SQLExecuteQueryOperator
|
||||||
from airflow.operators.mssql_operator import MsSqlOperator
|
|
||||||
from airflow.operators.mysql_operator import MySqlOperator
|
|
||||||
from airflow.operators.oracle_operator import OracleOperator
|
|
||||||
from airflow.operators.postgres_operator import PostgresOperator
|
|
||||||
from airflow.operators.sqlite_operator import SqliteOperator
|
|
||||||
|
|
||||||
JdbcOperator()
|
SQLExecuteQueryOperator()
|
||||||
MsSqlOperator()
|
SQLExecuteQueryOperator()
|
||||||
MySqlOperator()
|
SQLExecuteQueryOperator()
|
||||||
OracleOperator()
|
SQLExecuteQueryOperator()
|
||||||
PostgresOperator()
|
SQLExecuteQueryOperator()
|
||||||
SqliteOperator()
|
SQLExecuteQueryOperator()
|
||||||
|
|||||||
@@ -12,55 +12,59 @@ from airflow.macros.hive import (
|
|||||||
)
|
)
|
||||||
from airflow.operators.hive_operator import HiveOperator
|
from airflow.operators.hive_operator import HiveOperator
|
||||||
from airflow.operators.hive_stats_operator import HiveStatsCollectionOperator
|
from airflow.operators.hive_stats_operator import HiveStatsCollectionOperator
|
||||||
from airflow.operators.hive_to_mysql import (
|
from airflow.operators.hive_to_mysql import HiveToMySqlOperator
|
||||||
HiveToMySqlOperator,
|
|
||||||
HiveToMySqlTransfer,
|
|
||||||
)
|
|
||||||
from airflow.operators.hive_to_samba_operator import HiveToSambaOperator
|
from airflow.operators.hive_to_samba_operator import HiveToSambaOperator
|
||||||
from airflow.operators.mssql_to_hive import (
|
|
||||||
MsSqlToHiveOperator,
|
HIVE_QUEUE_PRIORITIES
|
||||||
MsSqlToHiveTransfer,
|
HiveCliHook()
|
||||||
)
|
HiveMetastoreHook()
|
||||||
from airflow.operators.mysql_to_hive import (
|
HiveServer2Hook()
|
||||||
MySqlToHiveOperator,
|
|
||||||
MySqlToHiveTransfer,
|
|
||||||
)
|
|
||||||
from airflow.operators.s3_to_hive_operator import (
|
|
||||||
S3ToHiveOperator,
|
|
||||||
S3ToHiveTransfer,
|
|
||||||
)
|
|
||||||
from airflow.sensors.hive_partition_sensor import HivePartitionSensor
|
|
||||||
from airflow.sensors.metastore_partition_sensor import MetastorePartitionSensor
|
|
||||||
from airflow.sensors.named_hive_partition_sensor import NamedHivePartitionSensor
|
|
||||||
|
|
||||||
closest_ds_partition()
|
closest_ds_partition()
|
||||||
max_partition()
|
max_partition()
|
||||||
|
|
||||||
HiveCliHook()
|
|
||||||
HiveMetastoreHook()
|
|
||||||
HiveServer2Hook()
|
|
||||||
HIVE_QUEUE_PRIORITIES
|
|
||||||
|
|
||||||
HiveOperator()
|
HiveOperator()
|
||||||
|
|
||||||
HiveStatsCollectionOperator()
|
HiveStatsCollectionOperator()
|
||||||
|
|
||||||
HiveToMySqlOperator()
|
HiveToMySqlOperator()
|
||||||
HiveToMySqlTransfer()
|
|
||||||
|
|
||||||
HiveToSambaOperator()
|
HiveToSambaOperator()
|
||||||
|
|
||||||
MsSqlToHiveOperator()
|
|
||||||
MsSqlToHiveTransfer()
|
from airflow.operators.hive_to_mysql import HiveToMySqlTransfer
|
||||||
|
|
||||||
|
HiveToMySqlTransfer()
|
||||||
|
|
||||||
|
from airflow.operators.mysql_to_hive import MySqlToHiveOperator
|
||||||
|
|
||||||
MySqlToHiveOperator()
|
MySqlToHiveOperator()
|
||||||
|
|
||||||
|
from airflow.operators.mysql_to_hive import MySqlToHiveTransfer
|
||||||
|
|
||||||
MySqlToHiveTransfer()
|
MySqlToHiveTransfer()
|
||||||
|
|
||||||
|
from airflow.operators.mssql_to_hive import MsSqlToHiveOperator
|
||||||
|
|
||||||
|
MsSqlToHiveOperator()
|
||||||
|
|
||||||
|
from airflow.operators.mssql_to_hive import MsSqlToHiveTransfer
|
||||||
|
|
||||||
|
MsSqlToHiveTransfer()
|
||||||
|
|
||||||
|
from airflow.operators.s3_to_hive_operator import S3ToHiveOperator
|
||||||
|
|
||||||
S3ToHiveOperator()
|
S3ToHiveOperator()
|
||||||
|
|
||||||
|
from airflow.operators.s3_to_hive_operator import S3ToHiveTransfer
|
||||||
|
|
||||||
S3ToHiveTransfer()
|
S3ToHiveTransfer()
|
||||||
|
|
||||||
|
from airflow.sensors.hive_partition_sensor import HivePartitionSensor
|
||||||
|
|
||||||
HivePartitionSensor()
|
HivePartitionSensor()
|
||||||
|
|
||||||
|
from airflow.sensors.metastore_partition_sensor import MetastorePartitionSensor
|
||||||
|
|
||||||
MetastorePartitionSensor()
|
MetastorePartitionSensor()
|
||||||
|
|
||||||
|
from airflow.sensors.named_hive_partition_sensor import NamedHivePartitionSensor
|
||||||
|
|
||||||
NamedHivePartitionSensor()
|
NamedHivePartitionSensor()
|
||||||
|
|||||||
@@ -16,14 +16,7 @@ from airflow.kubernetes.kube_client import (
|
|||||||
from airflow.kubernetes.kubernetes_helper_functions import (
|
from airflow.kubernetes.kubernetes_helper_functions import (
|
||||||
add_pod_suffix,
|
add_pod_suffix,
|
||||||
annotations_for_logging_task_metadata,
|
annotations_for_logging_task_metadata,
|
||||||
annotations_to_key,
|
|
||||||
create_pod_id,
|
create_pod_id,
|
||||||
get_logs_task_metadata,
|
|
||||||
rand_str,
|
|
||||||
)
|
|
||||||
from airflow.kubernetes.pod import (
|
|
||||||
Port,
|
|
||||||
Resources,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
ALL_NAMESPACES
|
ALL_NAMESPACES
|
||||||
@@ -37,21 +30,13 @@ _enable_tcp_keepalive()
|
|||||||
get_kube_client()
|
get_kube_client()
|
||||||
|
|
||||||
add_pod_suffix()
|
add_pod_suffix()
|
||||||
create_pod_id()
|
|
||||||
|
|
||||||
annotations_for_logging_task_metadata()
|
annotations_for_logging_task_metadata()
|
||||||
annotations_to_key()
|
create_pod_id()
|
||||||
get_logs_task_metadata()
|
|
||||||
rand_str()
|
|
||||||
|
|
||||||
Port()
|
|
||||||
Resources()
|
|
||||||
|
|
||||||
|
|
||||||
from airflow.kubernetes.pod_generator import (
|
from airflow.kubernetes.pod_generator import (
|
||||||
PodDefaults,
|
PodDefaults,
|
||||||
PodGenerator,
|
PodGenerator,
|
||||||
PodGeneratorDeprecated,
|
|
||||||
add_pod_suffix,
|
add_pod_suffix,
|
||||||
datetime_to_label_safe_datestring,
|
datetime_to_label_safe_datestring,
|
||||||
extend_object_field,
|
extend_object_field,
|
||||||
@@ -61,18 +46,16 @@ from airflow.kubernetes.pod_generator import (
|
|||||||
rand_str,
|
rand_str,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
PodDefaults()
|
||||||
|
PodGenerator()
|
||||||
|
add_pod_suffix()
|
||||||
datetime_to_label_safe_datestring()
|
datetime_to_label_safe_datestring()
|
||||||
extend_object_field()
|
extend_object_field()
|
||||||
label_safe_datestring_to_datetime()
|
label_safe_datestring_to_datetime()
|
||||||
make_safe_label_value()
|
make_safe_label_value()
|
||||||
merge_objects()
|
merge_objects()
|
||||||
PodGenerator()
|
|
||||||
PodDefaults()
|
|
||||||
PodGeneratorDeprecated()
|
|
||||||
add_pod_suffix()
|
|
||||||
rand_str()
|
rand_str()
|
||||||
|
|
||||||
|
|
||||||
from airflow.kubernetes.pod_generator_deprecated import (
|
from airflow.kubernetes.pod_generator_deprecated import (
|
||||||
PodDefaults,
|
PodDefaults,
|
||||||
PodGenerator,
|
PodGenerator,
|
||||||
@@ -90,7 +73,6 @@ make_safe_label_value()
|
|||||||
PodLauncher()
|
PodLauncher()
|
||||||
PodStatus()
|
PodStatus()
|
||||||
|
|
||||||
|
|
||||||
from airflow.kubernetes.pod_launcher_deprecated import (
|
from airflow.kubernetes.pod_launcher_deprecated import (
|
||||||
PodDefaults,
|
PodDefaults,
|
||||||
PodLauncher,
|
PodLauncher,
|
||||||
@@ -115,3 +97,17 @@ K8SModel()
|
|||||||
Secret()
|
Secret()
|
||||||
Volume()
|
Volume()
|
||||||
VolumeMount()
|
VolumeMount()
|
||||||
|
|
||||||
|
from airflow.kubernetes.kubernetes_helper_functions import (
|
||||||
|
annotations_to_key,
|
||||||
|
get_logs_task_metadata,
|
||||||
|
rand_str,
|
||||||
|
)
|
||||||
|
|
||||||
|
annotations_to_key()
|
||||||
|
get_logs_task_metadata()
|
||||||
|
rand_str()
|
||||||
|
|
||||||
|
from airflow.kubernetes.pod_generator import PodGeneratorDeprecated
|
||||||
|
|
||||||
|
PodGeneratorDeprecated()
|
||||||
|
|||||||
@@ -5,10 +5,6 @@ from airflow.operators.dagrun_operator import (
|
|||||||
TriggerDagRunLink,
|
TriggerDagRunLink,
|
||||||
TriggerDagRunOperator,
|
TriggerDagRunOperator,
|
||||||
)
|
)
|
||||||
from airflow.operators.dummy import (
|
|
||||||
DummyOperator,
|
|
||||||
EmptyOperator,
|
|
||||||
)
|
|
||||||
from airflow.operators.latest_only_operator import LatestOnlyOperator
|
from airflow.operators.latest_only_operator import LatestOnlyOperator
|
||||||
from airflow.operators.python_operator import (
|
from airflow.operators.python_operator import (
|
||||||
BranchPythonOperator,
|
BranchPythonOperator,
|
||||||
@@ -19,15 +15,12 @@ from airflow.operators.python_operator import (
|
|||||||
from airflow.sensors.external_task_sensor import (
|
from airflow.sensors.external_task_sensor import (
|
||||||
ExternalTaskMarker,
|
ExternalTaskMarker,
|
||||||
ExternalTaskSensor,
|
ExternalTaskSensor,
|
||||||
ExternalTaskSensorLink,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
BashOperator()
|
BashOperator()
|
||||||
|
|
||||||
TriggerDagRunLink()
|
TriggerDagRunLink()
|
||||||
TriggerDagRunOperator()
|
TriggerDagRunOperator()
|
||||||
DummyOperator()
|
|
||||||
EmptyOperator()
|
|
||||||
|
|
||||||
LatestOnlyOperator()
|
LatestOnlyOperator()
|
||||||
|
|
||||||
@@ -38,25 +31,48 @@ ShortCircuitOperator()
|
|||||||
|
|
||||||
ExternalTaskMarker()
|
ExternalTaskMarker()
|
||||||
ExternalTaskSensor()
|
ExternalTaskSensor()
|
||||||
ExternalTaskSensorLink()
|
|
||||||
|
|
||||||
from airflow.operators.dummy_operator import (
|
|
||||||
DummyOperator,
|
|
||||||
EmptyOperator,
|
|
||||||
)
|
|
||||||
|
|
||||||
DummyOperator()
|
|
||||||
EmptyOperator()
|
|
||||||
|
|
||||||
from airflow.hooks.subprocess import SubprocessResult
|
from airflow.hooks.subprocess import SubprocessResult
|
||||||
|
|
||||||
SubprocessResult()
|
SubprocessResult()
|
||||||
|
|
||||||
from airflow.hooks.subprocess import working_directory
|
from airflow.hooks.subprocess import working_directory
|
||||||
|
|
||||||
working_directory()
|
working_directory()
|
||||||
|
|
||||||
from airflow.operators.datetime import target_times_as_dates
|
from airflow.operators.datetime import target_times_as_dates
|
||||||
|
|
||||||
target_times_as_dates()
|
target_times_as_dates()
|
||||||
|
|
||||||
from airflow.operators.trigger_dagrun import TriggerDagRunLink
|
from airflow.operators.trigger_dagrun import TriggerDagRunLink
|
||||||
|
|
||||||
TriggerDagRunLink()
|
TriggerDagRunLink()
|
||||||
|
|
||||||
from airflow.sensors.external_task import ExternalTaskSensorLink
|
from airflow.sensors.external_task import ExternalTaskSensorLink
|
||||||
|
|
||||||
ExternalTaskSensorLink()
|
ExternalTaskSensorLink()
|
||||||
|
|
||||||
from airflow.sensors.time_delta import WaitSensor
|
from airflow.sensors.time_delta import WaitSensor
|
||||||
WaitSensor()
|
|
||||||
|
WaitSensor()
|
||||||
|
|
||||||
|
from airflow.operators.dummy import DummyOperator
|
||||||
|
|
||||||
|
DummyOperator()
|
||||||
|
|
||||||
|
from airflow.operators.dummy import EmptyOperator
|
||||||
|
|
||||||
|
EmptyOperator()
|
||||||
|
|
||||||
|
from airflow.operators.dummy_operator import DummyOperator
|
||||||
|
|
||||||
|
DummyOperator()
|
||||||
|
|
||||||
|
from airflow.operators.dummy_operator import EmptyOperator
|
||||||
|
|
||||||
|
EmptyOperator()
|
||||||
|
|
||||||
|
from airflow.sensors.external_task_sensor import ExternalTaskSensorLink
|
||||||
|
|
||||||
|
ExternalTaskSensorLink()
|
||||||
|
|||||||
@@ -9,19 +9,12 @@ from airflow.datasets import (
|
|||||||
expand_alias_to_datasets,
|
expand_alias_to_datasets,
|
||||||
)
|
)
|
||||||
from airflow.datasets.metadata import Metadata
|
from airflow.datasets.metadata import Metadata
|
||||||
from airflow.decorators import dag, setup, task, task_group, teardown
|
from airflow.decorators import (
|
||||||
from airflow.io.path import ObjectStoragePath
|
dag,
|
||||||
from airflow.io.storage import attach
|
setup,
|
||||||
from airflow.models import DAG as DAGFromModel
|
task,
|
||||||
from airflow.models import (
|
task_group,
|
||||||
Connection,
|
|
||||||
Variable,
|
|
||||||
)
|
)
|
||||||
from airflow.models.baseoperator import chain, chain_linear, cross_downstream
|
|
||||||
from airflow.models.baseoperatorlink import BaseOperatorLink
|
|
||||||
from airflow.models.dag import DAG as DAGFromDag
|
|
||||||
from airflow.timetables.datasets import DatasetOrTimeSchedule
|
|
||||||
from airflow.utils.dag_parsing_context import get_parsing_context
|
|
||||||
|
|
||||||
# airflow
|
# airflow
|
||||||
DatasetFromRoot()
|
DatasetFromRoot()
|
||||||
@@ -39,9 +32,22 @@ dag()
|
|||||||
task()
|
task()
|
||||||
task_group()
|
task_group()
|
||||||
setup()
|
setup()
|
||||||
|
from airflow.decorators import teardown
|
||||||
|
from airflow.io.path import ObjectStoragePath
|
||||||
|
from airflow.io.storage import attach
|
||||||
|
from airflow.models import DAG as DAGFromModel
|
||||||
|
from airflow.models import (
|
||||||
|
Connection,
|
||||||
|
Variable,
|
||||||
|
)
|
||||||
|
from airflow.models.baseoperator import chain, chain_linear, cross_downstream
|
||||||
|
from airflow.models.baseoperatorlink import BaseOperatorLink
|
||||||
|
from airflow.models.dag import DAG as DAGFromDag
|
||||||
|
|
||||||
|
# airflow.decorators
|
||||||
teardown()
|
teardown()
|
||||||
|
|
||||||
# airflow.io
|
# # airflow.io
|
||||||
ObjectStoragePath()
|
ObjectStoragePath()
|
||||||
attach()
|
attach()
|
||||||
|
|
||||||
@@ -60,6 +66,9 @@ BaseOperatorLink()
|
|||||||
|
|
||||||
# airflow.models.dag
|
# airflow.models.dag
|
||||||
DAGFromDag()
|
DAGFromDag()
|
||||||
|
from airflow.timetables.datasets import DatasetOrTimeSchedule
|
||||||
|
from airflow.utils.dag_parsing_context import get_parsing_context
|
||||||
|
|
||||||
# airflow.timetables.datasets
|
# airflow.timetables.datasets
|
||||||
DatasetOrTimeSchedule()
|
DatasetOrTimeSchedule()
|
||||||
|
|
||||||
|
|||||||
@@ -7,49 +7,71 @@ from airflow.operators.bash import BashOperator
|
|||||||
from airflow.operators.datetime import BranchDateTimeOperator
|
from airflow.operators.datetime import BranchDateTimeOperator
|
||||||
from airflow.operators.empty import EmptyOperator
|
from airflow.operators.empty import EmptyOperator
|
||||||
from airflow.operators.latest_only import LatestOnlyOperator
|
from airflow.operators.latest_only import LatestOnlyOperator
|
||||||
|
from airflow.operators.trigger_dagrun import TriggerDagRunOperator
|
||||||
|
from airflow.operators.weekday import BranchDayOfWeekOperator
|
||||||
|
from airflow.sensors.date_time import DateTimeSensor
|
||||||
|
|
||||||
|
FSHook()
|
||||||
|
PackageIndexHook()
|
||||||
|
SubprocessHook()
|
||||||
|
|
||||||
|
BashOperator()
|
||||||
|
BranchDateTimeOperator()
|
||||||
|
TriggerDagRunOperator()
|
||||||
|
EmptyOperator()
|
||||||
|
|
||||||
|
LatestOnlyOperator()
|
||||||
|
BranchDayOfWeekOperator()
|
||||||
|
DateTimeSensor()
|
||||||
|
|
||||||
from airflow.operators.python import (
|
from airflow.operators.python import (
|
||||||
BranchPythonOperator,
|
BranchPythonOperator,
|
||||||
PythonOperator,
|
PythonOperator,
|
||||||
PythonVirtualenvOperator,
|
PythonVirtualenvOperator,
|
||||||
ShortCircuitOperator,
|
ShortCircuitOperator,
|
||||||
)
|
)
|
||||||
from airflow.operators.trigger_dagrun import TriggerDagRunOperator
|
from airflow.sensors.date_time import DateTimeSensorAsync
|
||||||
from airflow.operators.weekday import BranchDayOfWeekOperator
|
|
||||||
from airflow.sensors.date_time import DateTimeSensor, DateTimeSensorAsync
|
|
||||||
from airflow.sensors.external_task import (
|
from airflow.sensors.external_task import (
|
||||||
ExternalTaskMarker,
|
ExternalTaskMarker,
|
||||||
ExternalTaskSensor,
|
ExternalTaskSensor,
|
||||||
|
)
|
||||||
|
from airflow.sensors.time_sensor import (
|
||||||
|
TimeSensor,
|
||||||
|
TimeSensorAsync,
|
||||||
)
|
)
|
||||||
from airflow.sensors.filesystem import FileSensor
|
from airflow.sensors.filesystem import FileSensor
|
||||||
from airflow.sensors.time_delta import TimeDeltaSensor, TimeDeltaSensorAsync
|
|
||||||
from airflow.sensors.time_sensor import TimeSensor, TimeSensorAsync
|
|
||||||
from airflow.sensors.weekday import DayOfWeekSensor
|
|
||||||
from airflow.triggers.external_task import DagStateTrigger, WorkflowTrigger
|
|
||||||
from airflow.triggers.file import FileTrigger
|
|
||||||
from airflow.triggers.temporal import DateTimeTrigger, TimeDeltaTrigger
|
|
||||||
|
|
||||||
FSHook()
|
BranchPythonOperator()
|
||||||
PackageIndexHook()
|
PythonOperator()
|
||||||
SubprocessHook()
|
PythonVirtualenvOperator()
|
||||||
BashOperator()
|
ShortCircuitOperator()
|
||||||
BranchDateTimeOperator()
|
DateTimeSensorAsync()
|
||||||
TriggerDagRunOperator()
|
ExternalTaskMarker()
|
||||||
EmptyOperator()
|
ExternalTaskSensor()
|
||||||
LatestOnlyOperator()
|
|
||||||
(
|
|
||||||
BranchPythonOperator(),
|
|
||||||
PythonOperator(),
|
|
||||||
PythonVirtualenvOperator(),
|
|
||||||
ShortCircuitOperator(),
|
|
||||||
)
|
|
||||||
BranchDayOfWeekOperator()
|
|
||||||
DateTimeSensor(), DateTimeSensorAsync()
|
|
||||||
ExternalTaskMarker(), ExternalTaskSensor()
|
|
||||||
FileSensor()
|
FileSensor()
|
||||||
TimeSensor(), TimeSensorAsync()
|
TimeSensor()
|
||||||
TimeDeltaSensor(), TimeDeltaSensorAsync()
|
TimeSensorAsync()
|
||||||
|
|
||||||
|
from airflow.sensors.time_delta import (
|
||||||
|
TimeDeltaSensor,
|
||||||
|
TimeDeltaSensorAsync,
|
||||||
|
)
|
||||||
|
from airflow.sensors.weekday import DayOfWeekSensor
|
||||||
|
from airflow.triggers.external_task import (
|
||||||
|
DagStateTrigger,
|
||||||
|
WorkflowTrigger,
|
||||||
|
)
|
||||||
|
from airflow.triggers.file import FileTrigger
|
||||||
|
from airflow.triggers.temporal import (
|
||||||
|
DateTimeTrigger,
|
||||||
|
TimeDeltaTrigger,
|
||||||
|
)
|
||||||
|
|
||||||
|
TimeDeltaSensor()
|
||||||
|
TimeDeltaSensorAsync()
|
||||||
DayOfWeekSensor()
|
DayOfWeekSensor()
|
||||||
DagStateTrigger(), WorkflowTrigger()
|
DagStateTrigger()
|
||||||
|
WorkflowTrigger()
|
||||||
FileTrigger()
|
FileTrigger()
|
||||||
DateTimeTrigger(), TimeDeltaTrigger()
|
DateTimeTrigger()
|
||||||
|
TimeDeltaTrigger()
|
||||||
|
|||||||
@@ -178,3 +178,38 @@ async def unknown_1(other: str = Depends(unknown_unresolved)): ...
|
|||||||
async def unknown_2(other: str = Depends(unknown_not_function)): ...
|
async def unknown_2(other: str = Depends(unknown_not_function)): ...
|
||||||
@app.get("/things/{thing_id}")
|
@app.get("/things/{thing_id}")
|
||||||
async def unknown_3(other: str = Depends(unknown_imported)): ...
|
async def unknown_3(other: str = Depends(unknown_imported)): ...
|
||||||
|
|
||||||
|
|
||||||
|
# Class dependencies
|
||||||
|
from pydantic import BaseModel
|
||||||
|
from dataclasses import dataclass
|
||||||
|
|
||||||
|
class PydanticParams(BaseModel):
|
||||||
|
my_id: int
|
||||||
|
|
||||||
|
|
||||||
|
class InitParams:
|
||||||
|
def __init__(self, my_id: int):
|
||||||
|
self.my_id = my_id
|
||||||
|
|
||||||
|
|
||||||
|
# Errors
|
||||||
|
@app.get("/{id}")
|
||||||
|
async def get_id_pydantic_full(
|
||||||
|
params: Annotated[PydanticParams, Depends(PydanticParams)],
|
||||||
|
): ...
|
||||||
|
@app.get("/{id}")
|
||||||
|
async def get_id_pydantic_short(params: Annotated[PydanticParams, Depends()]): ...
|
||||||
|
@app.get("/{id}")
|
||||||
|
async def get_id_init_not_annotated(params = Depends(InitParams)): ...
|
||||||
|
|
||||||
|
|
||||||
|
# No errors
|
||||||
|
@app.get("/{my_id}")
|
||||||
|
async def get_id_pydantic_full(
|
||||||
|
params: Annotated[PydanticParams, Depends(PydanticParams)],
|
||||||
|
): ...
|
||||||
|
@app.get("/{my_id}")
|
||||||
|
async def get_id_pydantic_short(params: Annotated[PydanticParams, Depends()]): ...
|
||||||
|
@app.get("/{my_id}")
|
||||||
|
async def get_id_init_not_annotated(params = Depends(InitParams)): ...
|
||||||
|
|||||||
@@ -145,3 +145,23 @@ def func():
|
|||||||
sleep = 10
|
sleep = 10
|
||||||
|
|
||||||
anyio.run(main)
|
anyio.run(main)
|
||||||
|
|
||||||
|
|
||||||
|
async def test_anyio_async115_helpers():
|
||||||
|
import anyio
|
||||||
|
|
||||||
|
await anyio.sleep(delay=1) # OK
|
||||||
|
await anyio.sleep(seconds=1) # OK
|
||||||
|
|
||||||
|
await anyio.sleep(delay=0) # ASYNC115
|
||||||
|
await anyio.sleep(seconds=0) # OK
|
||||||
|
|
||||||
|
|
||||||
|
async def test_trio_async115_helpers():
|
||||||
|
import trio
|
||||||
|
|
||||||
|
await trio.sleep(seconds=1) # OK
|
||||||
|
await trio.sleep(delay=1) # OK
|
||||||
|
|
||||||
|
await trio.sleep(seconds=0) # ASYNC115
|
||||||
|
await trio.sleep(delay=0) # OK
|
||||||
|
|||||||
@@ -108,3 +108,23 @@ async def import_from_anyio():
|
|||||||
|
|
||||||
# catch from import
|
# catch from import
|
||||||
await sleep(86401) # error: 116, "async"
|
await sleep(86401) # error: 116, "async"
|
||||||
|
|
||||||
|
|
||||||
|
async def test_anyio_async116_helpers():
|
||||||
|
import anyio
|
||||||
|
|
||||||
|
await anyio.sleep(delay=1) # OK
|
||||||
|
await anyio.sleep(seconds=1) # OK
|
||||||
|
|
||||||
|
await anyio.sleep(delay=86401) # ASYNC116
|
||||||
|
await anyio.sleep(seconds=86401) # OK
|
||||||
|
|
||||||
|
|
||||||
|
async def test_trio_async116_helpers():
|
||||||
|
import trio
|
||||||
|
|
||||||
|
await trio.sleep(seconds=1) # OK
|
||||||
|
await trio.sleep(delay=1) # OK
|
||||||
|
|
||||||
|
await trio.sleep(seconds=86401) # ASYNC116
|
||||||
|
await trio.sleep(delay=86401) # OK
|
||||||
|
|||||||
@@ -22,3 +22,8 @@ def my_func():
|
|||||||
|
|
||||||
# Implicit string concatenation
|
# Implicit string concatenation
|
||||||
"0.0.0.0" f"0.0.0.0{expr}0.0.0.0"
|
"0.0.0.0" f"0.0.0.0{expr}0.0.0.0"
|
||||||
|
|
||||||
|
# t-strings - all ok
|
||||||
|
t"0.0.0.0"
|
||||||
|
"0.0.0.0" t"0.0.0.0{expr}0.0.0.0"
|
||||||
|
"0.0.0.0" f"0.0.0.0{expr}0.0.0.0" t"0.0.0.0{expr}0.0.0.0"
|
||||||
|
|||||||
@@ -40,3 +40,7 @@ with tempfile.TemporaryDirectory(dir="/dev/shm") as d:
|
|||||||
|
|
||||||
with TemporaryDirectory(dir="/tmp") as d:
|
with TemporaryDirectory(dir="/tmp") as d:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
# ok (runtime error from t-string)
|
||||||
|
with open(t"/foo/bar", "w") as f:
|
||||||
|
f.write("def")
|
||||||
|
|||||||
@@ -169,3 +169,13 @@ query60 = f"""
|
|||||||
|
|
||||||
# https://github.com/astral-sh/ruff/issues/17967
|
# https://github.com/astral-sh/ruff/issues/17967
|
||||||
query61 = f"SELECT * FROM table" # skip expressionless f-strings
|
query61 = f"SELECT * FROM table" # skip expressionless f-strings
|
||||||
|
|
||||||
|
# t-strings
|
||||||
|
query62 = t"SELECT * FROM table"
|
||||||
|
query63 = t"""
|
||||||
|
SELECT *,
|
||||||
|
foo
|
||||||
|
FROM ({user_input}) raw
|
||||||
|
"""
|
||||||
|
query64 = f"update {t"{table}"} set var = {t"{var}"}"
|
||||||
|
query65 = t"update {f"{table}"} set var = {f"{var}"}"
|
||||||
|
|||||||
@@ -67,3 +67,6 @@ getattr(self.
|
|||||||
|
|
||||||
import builtins
|
import builtins
|
||||||
builtins.getattr(foo, "bar")
|
builtins.getattr(foo, "bar")
|
||||||
|
|
||||||
|
# Regression test for: https://github.com/astral-sh/ruff/issues/18353
|
||||||
|
setattr(foo, "__debug__", 0)
|
||||||
|
|||||||
@@ -91,3 +91,99 @@ _ = "\8""0" # fix should be "\80"
|
|||||||
_ = "\12""8" # fix should be "\128"
|
_ = "\12""8" # fix should be "\128"
|
||||||
_ = "\12""foo" # fix should be "\12foo"
|
_ = "\12""foo" # fix should be "\12foo"
|
||||||
_ = "\12" "" # fix should be "\12"
|
_ = "\12" "" # fix should be "\12"
|
||||||
|
|
||||||
|
|
||||||
|
# Mixed literal + non-literal scenarios
|
||||||
|
_ = (
|
||||||
|
"start" +
|
||||||
|
variable +
|
||||||
|
"end"
|
||||||
|
)
|
||||||
|
|
||||||
|
_ = (
|
||||||
|
f"format" +
|
||||||
|
func_call() +
|
||||||
|
"literal"
|
||||||
|
)
|
||||||
|
|
||||||
|
_ = (
|
||||||
|
rf"raw_f{x}" +
|
||||||
|
r"raw_normal"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# Different prefix combinations
|
||||||
|
_ = (
|
||||||
|
u"unicode" +
|
||||||
|
r"raw"
|
||||||
|
)
|
||||||
|
|
||||||
|
_ = (
|
||||||
|
rb"raw_bytes" +
|
||||||
|
b"normal_bytes"
|
||||||
|
)
|
||||||
|
|
||||||
|
_ = (
|
||||||
|
b"bytes" +
|
||||||
|
b"with_bytes"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Repeated concatenation
|
||||||
|
|
||||||
|
_ = ("a" +
|
||||||
|
"b" +
|
||||||
|
"c" +
|
||||||
|
"d" + "e"
|
||||||
|
)
|
||||||
|
|
||||||
|
_ = ("a"
|
||||||
|
+ "b"
|
||||||
|
+ "c"
|
||||||
|
+ "d"
|
||||||
|
+ "e"
|
||||||
|
)
|
||||||
|
|
||||||
|
_ = (
|
||||||
|
"start" +
|
||||||
|
variable + # comment
|
||||||
|
"end"
|
||||||
|
)
|
||||||
|
|
||||||
|
_ = (
|
||||||
|
"start" +
|
||||||
|
variable
|
||||||
|
# leading comment
|
||||||
|
+ "end"
|
||||||
|
)
|
||||||
|
|
||||||
|
_ = (
|
||||||
|
"first"
|
||||||
|
+ "second" # extra spaces around +
|
||||||
|
)
|
||||||
|
|
||||||
|
_ = (
|
||||||
|
"first" + # trailing spaces before +
|
||||||
|
"second"
|
||||||
|
)
|
||||||
|
|
||||||
|
_ = ((
|
||||||
|
"deep" +
|
||||||
|
"nesting"
|
||||||
|
))
|
||||||
|
|
||||||
|
_ = (
|
||||||
|
"contains + plus" +
|
||||||
|
"another string"
|
||||||
|
)
|
||||||
|
|
||||||
|
_ = (
|
||||||
|
"start"
|
||||||
|
# leading comment
|
||||||
|
+ "end"
|
||||||
|
)
|
||||||
|
|
||||||
|
_ = (
|
||||||
|
"start" +
|
||||||
|
# leading comment
|
||||||
|
"end"
|
||||||
|
)
|
||||||
|
|||||||
@@ -72,3 +72,5 @@ def not_warnings_dot_deprecated(
|
|||||||
|
|
||||||
@not_warnings_dot_deprecated("Not warnings.deprecated, so this one *should* lead to PYI053 in a stub!")
|
@not_warnings_dot_deprecated("Not warnings.deprecated, so this one *should* lead to PYI053 in a stub!")
|
||||||
def not_a_deprecated_function() -> None: ...
|
def not_a_deprecated_function() -> None: ...
|
||||||
|
|
||||||
|
baz: str = t"51 character stringgggggggggggggggggggggggggggggggg"
|
||||||
|
|||||||
@@ -80,3 +80,7 @@ x: TypeAlias = Literal["fooooooooooooooooooooooooooooooooooooooooooooooooooooooo
|
|||||||
|
|
||||||
# Ok
|
# Ok
|
||||||
y: TypeAlias = Annotated[int, "metadataaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"]
|
y: TypeAlias = Annotated[int, "metadataaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"]
|
||||||
|
|
||||||
|
ttoo: str = t"50 character stringggggggggggggggggggggggggggggggg" # OK
|
||||||
|
|
||||||
|
tbar: str = t"51 character stringgggggggggggggggggggggggggggggggg" # Error: PYI053
|
||||||
|
|||||||
@@ -39,3 +39,27 @@ f'\'normal\' {f'nested'} normal' # Q003
|
|||||||
f'\'normal\' {f'nested'} "double quotes"'
|
f'\'normal\' {f'nested'} "double quotes"'
|
||||||
f'\'normal\' {f'\'nested\' {'other'} normal'} "double quotes"' # Q003
|
f'\'normal\' {f'\'nested\' {'other'} normal'} "double quotes"' # Q003
|
||||||
f'\'normal\' {f'\'nested\' {'other'} "double quotes"'} normal' # Q00l
|
f'\'normal\' {f'\'nested\' {'other'} "double quotes"'} normal' # Q00l
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Same as above, but with t-strings
|
||||||
|
t'This is a \'string\'' # Q003
|
||||||
|
t'This is \\ a \\\'string\'' # Q003
|
||||||
|
t'"This" is a \'string\''
|
||||||
|
f"This is a 'string'"
|
||||||
|
f"\"This\" is a 'string'"
|
||||||
|
fr'This is a \'string\''
|
||||||
|
fR'This is a \'string\''
|
||||||
|
foo = (
|
||||||
|
t'This is a'
|
||||||
|
t'\'string\'' # Q003
|
||||||
|
)
|
||||||
|
t'\'foo\' {'nested'}' # Q003
|
||||||
|
t'\'foo\' {t'nested'}' # Q003
|
||||||
|
t'\'foo\' {t'\'nested\''} \'\'' # Q003
|
||||||
|
|
||||||
|
t'normal {t'nested'} normal'
|
||||||
|
t'\'normal\' {t'nested'} normal' # Q003
|
||||||
|
t'\'normal\' {t'nested'} "double quotes"'
|
||||||
|
t'\'normal\' {t'\'nested\' {'other'} normal'} "double quotes"' # Q003
|
||||||
|
t'\'normal\' {t'\'nested\' {'other'} "double quotes"'} normal' # Q00l
|
||||||
|
|||||||
@@ -37,3 +37,25 @@ f"\"normal\" {f"nested"} normal" # Q003
|
|||||||
f"\"normal\" {f"nested"} 'single quotes'"
|
f"\"normal\" {f"nested"} 'single quotes'"
|
||||||
f"\"normal\" {f"\"nested\" {"other"} normal"} 'single quotes'" # Q003
|
f"\"normal\" {f"\"nested\" {"other"} normal"} 'single quotes'" # Q003
|
||||||
f"\"normal\" {f"\"nested\" {"other"} 'single quotes'"} normal" # Q003
|
f"\"normal\" {f"\"nested\" {"other"} 'single quotes'"} normal" # Q003
|
||||||
|
|
||||||
|
|
||||||
|
# Same as above, but with t-strings
|
||||||
|
t"This is a \"string\""
|
||||||
|
t"'This' is a \"string\""
|
||||||
|
f'This is a "string"'
|
||||||
|
f'\'This\' is a "string"'
|
||||||
|
fr"This is a \"string\""
|
||||||
|
fR"This is a \"string\""
|
||||||
|
foo = (
|
||||||
|
t"This is a"
|
||||||
|
t"\"string\""
|
||||||
|
)
|
||||||
|
t"\"foo\" {"foo"}" # Q003
|
||||||
|
t"\"foo\" {t"foo"}" # Q003
|
||||||
|
t"\"foo\" {t"\"foo\""} \"\"" # Q003
|
||||||
|
|
||||||
|
t"normal {t"nested"} normal"
|
||||||
|
t"\"normal\" {t"nested"} normal" # Q003
|
||||||
|
t"\"normal\" {t"nested"} 'single quotes'"
|
||||||
|
t"\"normal\" {t"\"nested\" {"other"} normal"} 'single quotes'" # Q003
|
||||||
|
t"\"normal\" {t"\"nested\" {"other"} 'single quotes'"} normal" # Q003
|
||||||
|
|||||||
15
crates/ruff_linter/resources/test/fixtures/flake8_use_pathlib/PTH211.py
vendored
Normal file
15
crates/ruff_linter/resources/test/fixtures/flake8_use_pathlib/PTH211.py
vendored
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
import os
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
os.symlink("usr/bin/python", "tmp/python")
|
||||||
|
os.symlink(b"usr/bin/python", b"tmp/python")
|
||||||
|
Path("tmp/python").symlink_to("usr/bin/python") # Ok
|
||||||
|
|
||||||
|
os.symlink("usr/bin/python", "tmp/python", target_is_directory=True)
|
||||||
|
os.symlink(b"usr/bin/python", b"tmp/python", target_is_directory=True)
|
||||||
|
Path("tmp/python").symlink_to("usr/bin/python", target_is_directory=True) # Ok
|
||||||
|
|
||||||
|
fd = os.open(".", os.O_RDONLY)
|
||||||
|
os.symlink("source.txt", "link.txt", dir_fd=fd) # Ok: dir_fd is not supported by pathlib
|
||||||
|
os.close(fd)
|
||||||
@@ -266,3 +266,15 @@ def f():
|
|||||||
result = list() # this should be replaced with a comprehension
|
result = list() # this should be replaced with a comprehension
|
||||||
for i in values:
|
for i in values:
|
||||||
result.append(i + 1) # PERF401
|
result.append(i + 1) # PERF401
|
||||||
|
|
||||||
|
def f():
|
||||||
|
src = [1]
|
||||||
|
dst = []
|
||||||
|
|
||||||
|
for i in src:
|
||||||
|
if True if True else False:
|
||||||
|
dst.append(i)
|
||||||
|
|
||||||
|
for i in src:
|
||||||
|
if lambda: 0:
|
||||||
|
dst.append(i)
|
||||||
|
|||||||
@@ -151,3 +151,16 @@ def foo():
|
|||||||
result = {}
|
result = {}
|
||||||
for idx, name in indices, fruit:
|
for idx, name in indices, fruit:
|
||||||
result[name] = idx # PERF403
|
result[name] = idx # PERF403
|
||||||
|
|
||||||
|
|
||||||
|
def foo():
|
||||||
|
src = (("x", 1),)
|
||||||
|
dst = {}
|
||||||
|
|
||||||
|
for k, v in src:
|
||||||
|
if True if True else False:
|
||||||
|
dst[k] = v
|
||||||
|
|
||||||
|
for k, v in src:
|
||||||
|
if lambda: 0:
|
||||||
|
dst[k] = v
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
# Same as `W605_0.py` but using f-strings instead.
|
# Same as `W605_0.py` but using f-strings and t-strings instead.
|
||||||
|
|
||||||
#: W605:1:10
|
#: W605:1:10
|
||||||
regex = f'\.png$'
|
regex = f'\.png$'
|
||||||
@@ -66,3 +66,72 @@ s = f"TOTAL: {total}\nOK: {ok}\INCOMPLETE: {incomplete}\n"
|
|||||||
|
|
||||||
# Debug text (should trigger)
|
# Debug text (should trigger)
|
||||||
t = f"{'\InHere'=}"
|
t = f"{'\InHere'=}"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#: W605:1:10
|
||||||
|
regex = t'\.png$'
|
||||||
|
|
||||||
|
#: W605:2:1
|
||||||
|
regex = t'''
|
||||||
|
\.png$
|
||||||
|
'''
|
||||||
|
|
||||||
|
#: W605:2:6
|
||||||
|
f(
|
||||||
|
t'\_'
|
||||||
|
)
|
||||||
|
|
||||||
|
#: W605:4:6
|
||||||
|
t"""
|
||||||
|
multi-line
|
||||||
|
literal
|
||||||
|
with \_ somewhere
|
||||||
|
in the middle
|
||||||
|
"""
|
||||||
|
|
||||||
|
#: W605:1:38
|
||||||
|
value = t'new line\nand invalid escape \_ here'
|
||||||
|
|
||||||
|
|
||||||
|
#: Okay
|
||||||
|
regex = fr'\.png$'
|
||||||
|
regex = t'\\.png$'
|
||||||
|
regex = fr'''
|
||||||
|
\.png$
|
||||||
|
'''
|
||||||
|
regex = fr'''
|
||||||
|
\\.png$
|
||||||
|
'''
|
||||||
|
s = t'\\'
|
||||||
|
regex = t'\w' # noqa
|
||||||
|
regex = t'''
|
||||||
|
\w
|
||||||
|
''' # noqa
|
||||||
|
|
||||||
|
regex = t'\\\_'
|
||||||
|
value = t'\{{1}}'
|
||||||
|
value = t'\{1}'
|
||||||
|
value = t'{1:\}'
|
||||||
|
value = t"{t"\{1}"}"
|
||||||
|
value = rt"{t"\{1}"}"
|
||||||
|
|
||||||
|
# Okay
|
||||||
|
value = rt'\{{1}}'
|
||||||
|
value = rt'\{1}'
|
||||||
|
value = rt'{1:\}'
|
||||||
|
value = t"{rt"\{1}"}"
|
||||||
|
|
||||||
|
# Regression tests for https://github.com/astral-sh/ruff/issues/10434
|
||||||
|
t"{{}}+-\d"
|
||||||
|
t"\n{{}}+-\d+"
|
||||||
|
t"\n{{}}<7D>+-\d+"
|
||||||
|
|
||||||
|
# See https://github.com/astral-sh/ruff/issues/11491
|
||||||
|
total = 10
|
||||||
|
ok = 7
|
||||||
|
incomplete = 3
|
||||||
|
s = t"TOTAL: {total}\nOK: {ok}\INCOMPLETE: {incomplete}\n"
|
||||||
|
|
||||||
|
# Debug text (should trigger)
|
||||||
|
t = t"{'\InHere'=}"
|
||||||
|
|||||||
184
crates/ruff_linter/resources/test/fixtures/pylint/missing_maxsplit_arg.py
vendored
Normal file
184
crates/ruff_linter/resources/test/fixtures/pylint/missing_maxsplit_arg.py
vendored
Normal file
@@ -0,0 +1,184 @@
|
|||||||
|
SEQ = "1,2,3"
|
||||||
|
|
||||||
|
class Foo(str):
|
||||||
|
class_str = "1,2,3"
|
||||||
|
|
||||||
|
def split(self, sep=None, maxsplit=-1) -> list[str]:
|
||||||
|
return super().split(sep, maxsplit)
|
||||||
|
|
||||||
|
class Bar():
|
||||||
|
split = "1,2,3"
|
||||||
|
|
||||||
|
# Errors
|
||||||
|
## Test split called directly on string literal
|
||||||
|
"1,2,3".split(",")[0] # [missing-maxsplit-arg]
|
||||||
|
"1,2,3".split(",")[-1] # [missing-maxsplit-arg]
|
||||||
|
"1,2,3".rsplit(",")[0] # [missing-maxsplit-arg]
|
||||||
|
"1,2,3".rsplit(",")[-1] # [missing-maxsplit-arg]
|
||||||
|
|
||||||
|
## Test split called on string variable
|
||||||
|
SEQ.split(",")[0] # [missing-maxsplit-arg]
|
||||||
|
SEQ.split(",")[-1] # [missing-maxsplit-arg]
|
||||||
|
SEQ.rsplit(",")[0] # [missing-maxsplit-arg]
|
||||||
|
SEQ.rsplit(",")[-1] # [missing-maxsplit-arg]
|
||||||
|
|
||||||
|
## Test split called on class attribute
|
||||||
|
Foo.class_str.split(",")[0] # [missing-maxsplit-arg]
|
||||||
|
Foo.class_str.split(",")[-1] # [missing-maxsplit-arg]
|
||||||
|
Foo.class_str.rsplit(",")[0] # [missing-maxsplit-arg]
|
||||||
|
Foo.class_str.rsplit(",")[-1] # [missing-maxsplit-arg]
|
||||||
|
|
||||||
|
## Test split called on sliced string
|
||||||
|
"1,2,3"[::-1].split(",")[0] # [missing-maxsplit-arg]
|
||||||
|
"1,2,3"[::-1][::-1].split(",")[0] # [missing-maxsplit-arg]
|
||||||
|
SEQ[:3].split(",")[0] # [missing-maxsplit-arg]
|
||||||
|
Foo.class_str[1:3].split(",")[-1] # [missing-maxsplit-arg]
|
||||||
|
"1,2,3"[::-1].rsplit(",")[0] # [missing-maxsplit-arg]
|
||||||
|
SEQ[:3].rsplit(",")[0] # [missing-maxsplit-arg]
|
||||||
|
Foo.class_str[1:3].rsplit(",")[-1] # [missing-maxsplit-arg]
|
||||||
|
|
||||||
|
## Test sep given as named argument
|
||||||
|
"1,2,3".split(sep=",")[0] # [missing-maxsplit-arg]
|
||||||
|
"1,2,3".split(sep=",")[-1] # [missing-maxsplit-arg]
|
||||||
|
"1,2,3".rsplit(sep=",")[0] # [missing-maxsplit-arg]
|
||||||
|
"1,2,3".rsplit(sep=",")[-1] # [missing-maxsplit-arg]
|
||||||
|
|
||||||
|
## Special cases
|
||||||
|
"1,2,3".split("\n")[0] # [missing-maxsplit-arg]
|
||||||
|
"1,2,3".split("split")[-1] # [missing-maxsplit-arg]
|
||||||
|
"1,2,3".rsplit("rsplit")[0] # [missing-maxsplit-arg]
|
||||||
|
|
||||||
|
## Test class attribute named split
|
||||||
|
Bar.split.split(",")[0] # [missing-maxsplit-arg]
|
||||||
|
Bar.split.split(",")[-1] # [missing-maxsplit-arg]
|
||||||
|
Bar.split.rsplit(",")[0] # [missing-maxsplit-arg]
|
||||||
|
Bar.split.rsplit(",")[-1] # [missing-maxsplit-arg]
|
||||||
|
|
||||||
|
## Test unpacked dict literal kwargs
|
||||||
|
"1,2,3".split(**{"sep": ","})[0] # [missing-maxsplit-arg]
|
||||||
|
|
||||||
|
|
||||||
|
# OK
|
||||||
|
## Test not accessing the first or last element
|
||||||
|
### Test split called directly on string literal
|
||||||
|
"1,2,3".split(",")[1]
|
||||||
|
"1,2,3".split(",")[-2]
|
||||||
|
"1,2,3".rsplit(",")[1]
|
||||||
|
"1,2,3".rsplit(",")[-2]
|
||||||
|
|
||||||
|
### Test split called on string variable
|
||||||
|
SEQ.split(",")[1]
|
||||||
|
SEQ.split(",")[-2]
|
||||||
|
SEQ.rsplit(",")[1]
|
||||||
|
SEQ.rsplit(",")[-2]
|
||||||
|
|
||||||
|
### Test split called on class attribute
|
||||||
|
Foo.class_str.split(",")[1]
|
||||||
|
Foo.class_str.split(",")[-2]
|
||||||
|
Foo.class_str.rsplit(",")[1]
|
||||||
|
Foo.class_str.rsplit(",")[-2]
|
||||||
|
|
||||||
|
### Test split called on sliced string
|
||||||
|
"1,2,3"[::-1].split(",")[1]
|
||||||
|
SEQ[:3].split(",")[1]
|
||||||
|
Foo.class_str[1:3].split(",")[-2]
|
||||||
|
"1,2,3"[::-1].rsplit(",")[1]
|
||||||
|
SEQ[:3].rsplit(",")[1]
|
||||||
|
Foo.class_str[1:3].rsplit(",")[-2]
|
||||||
|
|
||||||
|
### Test sep given as named argument
|
||||||
|
"1,2,3".split(sep=",")[1]
|
||||||
|
"1,2,3".split(sep=",")[-2]
|
||||||
|
"1,2,3".rsplit(sep=",")[1]
|
||||||
|
"1,2,3".rsplit(sep=",")[-2]
|
||||||
|
|
||||||
|
## Test varying maxsplit argument
|
||||||
|
### str.split() tests
|
||||||
|
"1,2,3".split(sep=",", maxsplit=1)[-1]
|
||||||
|
"1,2,3".split(sep=",", maxsplit=1)[0]
|
||||||
|
"1,2,3".split(sep=",", maxsplit=2)[-1]
|
||||||
|
"1,2,3".split(sep=",", maxsplit=2)[0]
|
||||||
|
"1,2,3".split(sep=",", maxsplit=2)[1]
|
||||||
|
|
||||||
|
### str.rsplit() tests
|
||||||
|
"1,2,3".rsplit(sep=",", maxsplit=1)[-1]
|
||||||
|
"1,2,3".rsplit(sep=",", maxsplit=1)[0]
|
||||||
|
"1,2,3".rsplit(sep=",", maxsplit=2)[-1]
|
||||||
|
"1,2,3".rsplit(sep=",", maxsplit=2)[0]
|
||||||
|
"1,2,3".rsplit(sep=",", maxsplit=2)[1]
|
||||||
|
|
||||||
|
## Test user-defined split
|
||||||
|
Foo("1,2,3").split(",")[0]
|
||||||
|
Foo("1,2,3").split(",")[-1]
|
||||||
|
Foo("1,2,3").rsplit(",")[0]
|
||||||
|
Foo("1,2,3").rsplit(",")[-1]
|
||||||
|
|
||||||
|
## Test split called on sliced list
|
||||||
|
["1", "2", "3"][::-1].split(",")[0]
|
||||||
|
|
||||||
|
## Test class attribute named split
|
||||||
|
Bar.split[0]
|
||||||
|
Bar.split[-1]
|
||||||
|
Bar.split[0]
|
||||||
|
Bar.split[-1]
|
||||||
|
|
||||||
|
## Test unpacked dict literal kwargs
|
||||||
|
"1,2,3".split(",", **{"maxsplit": 1})[0]
|
||||||
|
"1,2,3".split(**{"sep": ",", "maxsplit": 1})[0]
|
||||||
|
|
||||||
|
|
||||||
|
# TODO
|
||||||
|
|
||||||
|
## Test variable split result index
|
||||||
|
## TODO: These require the ability to resolve a variable name to a value
|
||||||
|
# Errors
|
||||||
|
result_index = 0
|
||||||
|
"1,2,3".split(",")[result_index] # TODO: [missing-maxsplit-arg]
|
||||||
|
result_index = -1
|
||||||
|
"1,2,3".split(",")[result_index] # TODO: [missing-maxsplit-arg]
|
||||||
|
# OK
|
||||||
|
result_index = 1
|
||||||
|
"1,2,3".split(",")[result_index]
|
||||||
|
result_index = -2
|
||||||
|
"1,2,3".split(",")[result_index]
|
||||||
|
|
||||||
|
|
||||||
|
## Test split result index modified in loop
|
||||||
|
## TODO: These require the ability to recognize being in a loop where:
|
||||||
|
## - the result of split called on a string is indexed by a variable
|
||||||
|
## - the variable index above is modified
|
||||||
|
# OK
|
||||||
|
result_index = 0
|
||||||
|
for j in range(3):
|
||||||
|
print(SEQ.split(",")[result_index])
|
||||||
|
result_index = result_index + 1
|
||||||
|
|
||||||
|
|
||||||
|
## Test accessor
|
||||||
|
## TODO: These require the ability to get the return type of a method
|
||||||
|
## (possibly via `typing::is_string`)
|
||||||
|
class Baz():
|
||||||
|
def __init__(self):
|
||||||
|
self.my_str = "1,2,3"
|
||||||
|
|
||||||
|
def get_string(self) -> str:
|
||||||
|
return self.my_str
|
||||||
|
|
||||||
|
# Errors
|
||||||
|
Baz().get_string().split(",")[0] # TODO: [missing-maxsplit-arg]
|
||||||
|
Baz().get_string().split(",")[-1] # TODO: [missing-maxsplit-arg]
|
||||||
|
# OK
|
||||||
|
Baz().get_string().split(",")[1]
|
||||||
|
Baz().get_string().split(",")[-2]
|
||||||
|
|
||||||
|
|
||||||
|
## Test unpacked dict instance kwargs
|
||||||
|
## TODO: These require the ability to resolve a dict variable name to a value
|
||||||
|
# Errors
|
||||||
|
kwargs_without_maxsplit = {"seq": ","}
|
||||||
|
"1,2,3".split(**kwargs_without_maxsplit)[0] # TODO: [missing-maxsplit-arg]
|
||||||
|
# OK
|
||||||
|
kwargs_with_maxsplit = {"maxsplit": 1}
|
||||||
|
"1,2,3".split(",", **kwargs_with_maxsplit)[0] # TODO: false positive
|
||||||
|
kwargs_with_maxsplit = {"sep": ",", "maxsplit": 1}
|
||||||
|
"1,2,3".split(**kwargs_with_maxsplit)[0] # TODO: false positive
|
||||||
@@ -12,3 +12,4 @@ if True:
|
|||||||
if True:
|
if True:
|
||||||
from __future__ import generator_stop
|
from __future__ import generator_stop
|
||||||
from __future__ import invalid_module, generators
|
from __future__ import invalid_module, generators
|
||||||
|
from __future__ import generators # comment
|
||||||
|
|||||||
84
crates/ruff_linter/resources/test/fixtures/pyupgrade/UP050.py
vendored
Normal file
84
crates/ruff_linter/resources/test/fixtures/pyupgrade/UP050.py
vendored
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
class A:
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
|
class A(metaclass=type):
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
|
class A(
|
||||||
|
metaclass=type
|
||||||
|
):
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
|
class A(
|
||||||
|
metaclass=type
|
||||||
|
#
|
||||||
|
):
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
|
class A(
|
||||||
|
#
|
||||||
|
metaclass=type
|
||||||
|
):
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
|
class A(
|
||||||
|
metaclass=type,
|
||||||
|
#
|
||||||
|
):
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
|
class A(
|
||||||
|
#
|
||||||
|
metaclass=type,
|
||||||
|
#
|
||||||
|
):
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
|
class B(A, metaclass=type):
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
|
class B(
|
||||||
|
A,
|
||||||
|
metaclass=type,
|
||||||
|
):
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
|
class B(
|
||||||
|
A,
|
||||||
|
# comment
|
||||||
|
metaclass=type,
|
||||||
|
):
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
|
def foo():
|
||||||
|
class A(metaclass=type):
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
|
class A(
|
||||||
|
metaclass=type # comment
|
||||||
|
,
|
||||||
|
):
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
|
type = str
|
||||||
|
|
||||||
|
class Foo(metaclass=type):
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
|
import builtins
|
||||||
|
|
||||||
|
class A(metaclass=builtins.type):
|
||||||
|
...
|
||||||
@@ -43,7 +43,6 @@ def func():
|
|||||||
|
|
||||||
import builtins
|
import builtins
|
||||||
|
|
||||||
|
|
||||||
with builtins.open("FURB129.py") as f:
|
with builtins.open("FURB129.py") as f:
|
||||||
for line in f.readlines():
|
for line in f.readlines():
|
||||||
pass
|
pass
|
||||||
@@ -51,7 +50,6 @@ with builtins.open("FURB129.py") as f:
|
|||||||
|
|
||||||
from builtins import open as o
|
from builtins import open as o
|
||||||
|
|
||||||
|
|
||||||
with o("FURB129.py") as f:
|
with o("FURB129.py") as f:
|
||||||
for line in f.readlines():
|
for line in f.readlines():
|
||||||
pass
|
pass
|
||||||
@@ -89,3 +87,18 @@ with open("FURB129.py") as f:
|
|||||||
pass
|
pass
|
||||||
for _not_line in f.readline():
|
for _not_line in f.readline():
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
# https://github.com/astral-sh/ruff/issues/18231
|
||||||
|
with open("furb129.py") as f:
|
||||||
|
for line in (f).readlines():
|
||||||
|
pass
|
||||||
|
|
||||||
|
with open("furb129.py") as f:
|
||||||
|
[line for line in (f).readlines()]
|
||||||
|
|
||||||
|
|
||||||
|
with open("furb129.py") as f:
|
||||||
|
for line in (((f))).readlines():
|
||||||
|
pass
|
||||||
|
for line in(f).readlines():
|
||||||
|
pass
|
||||||
|
|||||||
53
crates/ruff_linter/resources/test/fixtures/refurb/FURB171_1.py
vendored
Normal file
53
crates/ruff_linter/resources/test/fixtures/refurb/FURB171_1.py
vendored
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
# Errors.
|
||||||
|
|
||||||
|
if 1 in set([1]):
|
||||||
|
print("Single-element set")
|
||||||
|
|
||||||
|
if 1 in set((1,)):
|
||||||
|
print("Single-element set")
|
||||||
|
|
||||||
|
if 1 in set({1}):
|
||||||
|
print("Single-element set")
|
||||||
|
|
||||||
|
if 1 in frozenset([1]):
|
||||||
|
print("Single-element set")
|
||||||
|
|
||||||
|
if 1 in frozenset((1,)):
|
||||||
|
print("Single-element set")
|
||||||
|
|
||||||
|
if 1 in frozenset({1}):
|
||||||
|
print("Single-element set")
|
||||||
|
|
||||||
|
if 1 in set(set([1])):
|
||||||
|
print('Recursive solution')
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Non-errors.
|
||||||
|
|
||||||
|
if 1 in set((1, 2)):
|
||||||
|
pass
|
||||||
|
|
||||||
|
if 1 in set([1, 2]):
|
||||||
|
pass
|
||||||
|
|
||||||
|
if 1 in set({1, 2}):
|
||||||
|
pass
|
||||||
|
|
||||||
|
if 1 in frozenset((1, 2)):
|
||||||
|
pass
|
||||||
|
|
||||||
|
if 1 in frozenset([1, 2]):
|
||||||
|
pass
|
||||||
|
|
||||||
|
if 1 in frozenset({1, 2}):
|
||||||
|
pass
|
||||||
|
|
||||||
|
if 1 in set(1,):
|
||||||
|
pass
|
||||||
|
|
||||||
|
if 1 in set(1,2):
|
||||||
|
pass
|
||||||
|
|
||||||
|
if 1 in set((x for x in range(2))):
|
||||||
|
pass
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
use ruff_diagnostics::{Diagnostic, Fix};
|
|
||||||
use ruff_text_size::Ranged;
|
use ruff_text_size::Ranged;
|
||||||
|
|
||||||
|
use crate::Fix;
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
use crate::codes::Rule;
|
use crate::codes::Rule;
|
||||||
use crate::rules::{
|
use crate::rules::{
|
||||||
@@ -38,92 +38,64 @@ pub(crate) fn bindings(checker: &Checker) {
|
|||||||
.dummy_variable_rgx
|
.dummy_variable_rgx
|
||||||
.is_match(binding.name(checker.source()))
|
.is_match(binding.name(checker.source()))
|
||||||
{
|
{
|
||||||
let mut diagnostic = Diagnostic::new(
|
checker
|
||||||
pyflakes::rules::UnusedVariable {
|
.report_diagnostic(
|
||||||
name: binding.name(checker.source()).to_string(),
|
pyflakes::rules::UnusedVariable {
|
||||||
},
|
name: binding.name(checker.source()).to_string(),
|
||||||
binding.range(),
|
},
|
||||||
);
|
binding.range(),
|
||||||
diagnostic.try_set_fix(|| {
|
)
|
||||||
pyflakes::fixes::remove_exception_handler_assignment(binding, checker.locator)
|
.try_set_fix(|| {
|
||||||
|
pyflakes::fixes::remove_exception_handler_assignment(
|
||||||
|
binding,
|
||||||
|
checker.locator,
|
||||||
|
)
|
||||||
.map(Fix::safe_edit)
|
.map(Fix::safe_edit)
|
||||||
});
|
});
|
||||||
checker.report_diagnostic(diagnostic);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if checker.enabled(Rule::InvalidAllFormat) {
|
if checker.enabled(Rule::InvalidAllFormat) {
|
||||||
if let Some(diagnostic) = pylint::rules::invalid_all_format(binding) {
|
pylint::rules::invalid_all_format(checker, binding);
|
||||||
checker.report_diagnostic(diagnostic);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if checker.enabled(Rule::InvalidAllObject) {
|
if checker.enabled(Rule::InvalidAllObject) {
|
||||||
if let Some(diagnostic) = pylint::rules::invalid_all_object(binding) {
|
pylint::rules::invalid_all_object(checker, binding);
|
||||||
checker.report_diagnostic(diagnostic);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if checker.enabled(Rule::NonAsciiName) {
|
if checker.enabled(Rule::NonAsciiName) {
|
||||||
if let Some(diagnostic) = pylint::rules::non_ascii_name(binding, checker.locator) {
|
pylint::rules::non_ascii_name(checker, binding);
|
||||||
checker.report_diagnostic(diagnostic);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if checker.enabled(Rule::UnconventionalImportAlias) {
|
if checker.enabled(Rule::UnconventionalImportAlias) {
|
||||||
if let Some(diagnostic) = flake8_import_conventions::rules::unconventional_import_alias(
|
flake8_import_conventions::rules::unconventional_import_alias(
|
||||||
checker,
|
checker,
|
||||||
binding,
|
binding,
|
||||||
&checker.settings.flake8_import_conventions.aliases,
|
&checker.settings.flake8_import_conventions.aliases,
|
||||||
) {
|
);
|
||||||
checker.report_diagnostic(diagnostic);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if checker.enabled(Rule::UnaliasedCollectionsAbcSetImport) {
|
if checker.enabled(Rule::UnaliasedCollectionsAbcSetImport) {
|
||||||
if let Some(diagnostic) =
|
flake8_pyi::rules::unaliased_collections_abc_set_import(checker, binding);
|
||||||
flake8_pyi::rules::unaliased_collections_abc_set_import(checker, binding)
|
|
||||||
{
|
|
||||||
checker.report_diagnostic(diagnostic);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if !checker.source_type.is_stub() && checker.enabled(Rule::UnquotedTypeAlias) {
|
if !checker.source_type.is_stub() && checker.enabled(Rule::UnquotedTypeAlias) {
|
||||||
flake8_type_checking::rules::unquoted_type_alias(checker, binding);
|
flake8_type_checking::rules::unquoted_type_alias(checker, binding);
|
||||||
}
|
}
|
||||||
if checker.enabled(Rule::UnsortedDunderSlots) {
|
if checker.enabled(Rule::UnsortedDunderSlots) {
|
||||||
if let Some(diagnostic) = ruff::rules::sort_dunder_slots(checker, binding) {
|
ruff::rules::sort_dunder_slots(checker, binding);
|
||||||
checker.report_diagnostic(diagnostic);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if checker.enabled(Rule::UsedDummyVariable) {
|
if checker.enabled(Rule::UsedDummyVariable) {
|
||||||
if let Some(diagnostic) = ruff::rules::used_dummy_variable(checker, binding, binding_id)
|
ruff::rules::used_dummy_variable(checker, binding, binding_id);
|
||||||
{
|
|
||||||
checker.report_diagnostic(diagnostic);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if checker.enabled(Rule::AssignmentInAssert) {
|
if checker.enabled(Rule::AssignmentInAssert) {
|
||||||
if let Some(diagnostic) = ruff::rules::assignment_in_assert(checker, binding) {
|
ruff::rules::assignment_in_assert(checker, binding);
|
||||||
checker.report_diagnostic(diagnostic);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if checker.enabled(Rule::PytestUnittestRaisesAssertion) {
|
if checker.enabled(Rule::PytestUnittestRaisesAssertion) {
|
||||||
if let Some(diagnostic) =
|
flake8_pytest_style::rules::unittest_raises_assertion_binding(checker, binding);
|
||||||
flake8_pytest_style::rules::unittest_raises_assertion_binding(checker, binding)
|
|
||||||
{
|
|
||||||
checker.report_diagnostic(diagnostic);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if checker.enabled(Rule::ForLoopWrites) {
|
if checker.enabled(Rule::ForLoopWrites) {
|
||||||
if let Some(diagnostic) = refurb::rules::for_loop_writes_binding(checker, binding) {
|
refurb::rules::for_loop_writes_binding(checker, binding);
|
||||||
checker.report_diagnostic(diagnostic);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if checker.enabled(Rule::CustomTypeVarForSelf) {
|
if checker.enabled(Rule::CustomTypeVarForSelf) {
|
||||||
if let Some(diagnostic) =
|
flake8_pyi::rules::custom_type_var_instead_of_self(checker, binding);
|
||||||
flake8_pyi::rules::custom_type_var_instead_of_self(checker, binding)
|
|
||||||
{
|
|
||||||
checker.report_diagnostic(diagnostic);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if checker.enabled(Rule::PrivateTypeParameter) {
|
if checker.enabled(Rule::PrivateTypeParameter) {
|
||||||
if let Some(diagnostic) = pyupgrade::rules::private_type_parameter(checker, binding) {
|
pyupgrade::rules::private_type_parameter(checker, binding);
|
||||||
checker.report_diagnostic(diagnostic);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
use ruff_diagnostics::{Diagnostic, Fix};
|
|
||||||
use ruff_python_semantic::analyze::visibility;
|
use ruff_python_semantic::analyze::visibility;
|
||||||
use ruff_python_semantic::{Binding, BindingKind, Imported, ResolvedReference, ScopeKind};
|
use ruff_python_semantic::{Binding, BindingKind, Imported, ResolvedReference, ScopeKind};
|
||||||
use ruff_text_size::Ranged;
|
use ruff_text_size::Ranged;
|
||||||
use rustc_hash::FxHashMap;
|
use rustc_hash::FxHashMap;
|
||||||
|
|
||||||
|
use crate::Fix;
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
use crate::codes::Rule;
|
use crate::codes::Rule;
|
||||||
use crate::fix;
|
use crate::fix;
|
||||||
@@ -112,12 +112,12 @@ pub(crate) fn deferred_scopes(checker: &Checker) {
|
|||||||
.map(|id| checker.semantic.reference(*id))
|
.map(|id| checker.semantic.reference(*id))
|
||||||
.all(ResolvedReference::is_load)
|
.all(ResolvedReference::is_load)
|
||||||
{
|
{
|
||||||
checker.report_diagnostic(Diagnostic::new(
|
checker.report_diagnostic(
|
||||||
pylint::rules::GlobalVariableNotAssigned {
|
pylint::rules::GlobalVariableNotAssigned {
|
||||||
name: (*name).to_string(),
|
name: (*name).to_string(),
|
||||||
},
|
},
|
||||||
binding.range(),
|
binding.range(),
|
||||||
));
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -146,12 +146,12 @@ pub(crate) fn deferred_scopes(checker: &Checker) {
|
|||||||
if scope.kind.is_generator() {
|
if scope.kind.is_generator() {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
checker.report_diagnostic(Diagnostic::new(
|
checker.report_diagnostic(
|
||||||
pylint::rules::RedefinedArgumentFromLocal {
|
pylint::rules::RedefinedArgumentFromLocal {
|
||||||
name: name.to_string(),
|
name: name.to_string(),
|
||||||
},
|
},
|
||||||
binding.range(),
|
binding.range(),
|
||||||
));
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -186,13 +186,13 @@ pub(crate) fn deferred_scopes(checker: &Checker) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
checker.report_diagnostic(Diagnostic::new(
|
checker.report_diagnostic(
|
||||||
pyflakes::rules::ImportShadowedByLoopVar {
|
pyflakes::rules::ImportShadowedByLoopVar {
|
||||||
name: name.to_string(),
|
name: name.to_string(),
|
||||||
row: checker.compute_source_row(shadowed.start()),
|
row: checker.compute_source_row(shadowed.start()),
|
||||||
},
|
},
|
||||||
binding.range(),
|
binding.range(),
|
||||||
));
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -331,7 +331,7 @@ pub(crate) fn deferred_scopes(checker: &Checker) {
|
|||||||
// Create diagnostics for each statement.
|
// Create diagnostics for each statement.
|
||||||
for (source, entries) in &redefinitions {
|
for (source, entries) in &redefinitions {
|
||||||
for (shadowed, binding) in entries {
|
for (shadowed, binding) in entries {
|
||||||
let mut diagnostic = Diagnostic::new(
|
let mut diagnostic = checker.report_diagnostic(
|
||||||
pyflakes::rules::RedefinedWhileUnused {
|
pyflakes::rules::RedefinedWhileUnused {
|
||||||
name: binding.name(checker.source()).to_string(),
|
name: binding.name(checker.source()).to_string(),
|
||||||
row: checker.compute_source_row(shadowed.start()),
|
row: checker.compute_source_row(shadowed.start()),
|
||||||
@@ -346,8 +346,6 @@ pub(crate) fn deferred_scopes(checker: &Checker) {
|
|||||||
if let Some(fix) = source.as_ref().and_then(|source| fixes.get(source)) {
|
if let Some(fix) = source.as_ref().and_then(|source| fixes.get(source)) {
|
||||||
diagnostic.set_fix(fix.clone());
|
diagnostic.set_fix(fix.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
checker.report_diagnostic(diagnostic);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,14 +17,7 @@ pub(crate) fn except_handler(except_handler: &ExceptHandler, checker: &Checker)
|
|||||||
range: _,
|
range: _,
|
||||||
}) => {
|
}) => {
|
||||||
if checker.enabled(Rule::BareExcept) {
|
if checker.enabled(Rule::BareExcept) {
|
||||||
if let Some(diagnostic) = pycodestyle::rules::bare_except(
|
pycodestyle::rules::bare_except(checker, type_.as_deref(), body, except_handler);
|
||||||
type_.as_deref(),
|
|
||||||
body,
|
|
||||||
except_handler,
|
|
||||||
checker.locator,
|
|
||||||
) {
|
|
||||||
checker.report_diagnostic(diagnostic);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if checker.enabled(Rule::RaiseWithoutFromInsideExcept) {
|
if checker.enabled(Rule::RaiseWithoutFromInsideExcept) {
|
||||||
flake8_bugbear::rules::raise_without_from_inside_except(
|
flake8_bugbear::rules::raise_without_from_inside_except(
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
use ruff_python_ast::{self as ast, Arguments, 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_python_ast::types::Node;
|
use ruff_python_ast::types::Node;
|
||||||
use ruff_python_semantic::ScopeKind;
|
use ruff_python_semantic::ScopeKind;
|
||||||
use ruff_python_semantic::analyze::typing;
|
use ruff_python_semantic::analyze::typing;
|
||||||
@@ -178,6 +176,9 @@ pub(crate) fn expression(expr: &Expr, checker: &Checker) {
|
|||||||
if checker.enabled(Rule::Airflow3Removal) {
|
if checker.enabled(Rule::Airflow3Removal) {
|
||||||
airflow::rules::airflow_3_removal_expr(checker, expr);
|
airflow::rules::airflow_3_removal_expr(checker, expr);
|
||||||
}
|
}
|
||||||
|
if checker.enabled(Rule::MissingMaxsplitArg) {
|
||||||
|
pylint::rules::missing_maxsplit_arg(checker, value, slice, expr);
|
||||||
|
}
|
||||||
pandas_vet::rules::subscript(checker, value, expr);
|
pandas_vet::rules::subscript(checker, value, expr);
|
||||||
}
|
}
|
||||||
Expr::Tuple(ast::ExprTuple {
|
Expr::Tuple(ast::ExprTuple {
|
||||||
@@ -195,14 +196,13 @@ pub(crate) fn expression(expr: &Expr, checker: &Checker) {
|
|||||||
let check_too_many_expressions = checker.enabled(Rule::ExpressionsInStarAssignment);
|
let check_too_many_expressions = checker.enabled(Rule::ExpressionsInStarAssignment);
|
||||||
let check_two_starred_expressions =
|
let check_two_starred_expressions =
|
||||||
checker.enabled(Rule::MultipleStarredExpressions);
|
checker.enabled(Rule::MultipleStarredExpressions);
|
||||||
if let Some(diagnostic) = pyflakes::rules::starred_expressions(
|
pyflakes::rules::starred_expressions(
|
||||||
|
checker,
|
||||||
elts,
|
elts,
|
||||||
check_too_many_expressions,
|
check_too_many_expressions,
|
||||||
check_two_starred_expressions,
|
check_two_starred_expressions,
|
||||||
expr.range(),
|
expr.range(),
|
||||||
) {
|
);
|
||||||
checker.report_diagnostic(diagnostic);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Expr::Name(ast::ExprName { id, ctx, range }) => {
|
Expr::Name(ast::ExprName { id, ctx, range }) => {
|
||||||
@@ -527,12 +527,12 @@ pub(crate) fn expression(expr: &Expr, checker: &Checker) {
|
|||||||
match pyflakes::format::FormatSummary::try_from(string_value.to_str()) {
|
match pyflakes::format::FormatSummary::try_from(string_value.to_str()) {
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
if checker.enabled(Rule::StringDotFormatInvalidFormat) {
|
if checker.enabled(Rule::StringDotFormatInvalidFormat) {
|
||||||
checker.report_diagnostic(Diagnostic::new(
|
checker.report_diagnostic(
|
||||||
pyflakes::rules::StringDotFormatInvalidFormat {
|
pyflakes::rules::StringDotFormatInvalidFormat {
|
||||||
message: pyflakes::format::error_to_string(&e),
|
message: pyflakes::format::error_to_string(&e),
|
||||||
},
|
},
|
||||||
location,
|
location,
|
||||||
));
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(summary) => {
|
Ok(summary) => {
|
||||||
@@ -936,9 +936,7 @@ pub(crate) fn expression(expr: &Expr, checker: &Checker) {
|
|||||||
pylint::rules::repeated_keyword_argument(checker, call);
|
pylint::rules::repeated_keyword_argument(checker, call);
|
||||||
}
|
}
|
||||||
if checker.enabled(Rule::PytestPatchWithLambda) {
|
if checker.enabled(Rule::PytestPatchWithLambda) {
|
||||||
if let Some(diagnostic) = flake8_pytest_style::rules::patch_with_lambda(call) {
|
flake8_pytest_style::rules::patch_with_lambda(checker, call);
|
||||||
checker.report_diagnostic(diagnostic);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if checker.any_enabled(&[
|
if checker.any_enabled(&[
|
||||||
Rule::PytestParametrizeNamesWrongType,
|
Rule::PytestParametrizeNamesWrongType,
|
||||||
@@ -1041,6 +1039,7 @@ pub(crate) fn expression(expr: &Expr, checker: &Checker) {
|
|||||||
Rule::OsPathGetctime,
|
Rule::OsPathGetctime,
|
||||||
Rule::Glob,
|
Rule::Glob,
|
||||||
Rule::OsListdir,
|
Rule::OsListdir,
|
||||||
|
Rule::OsSymlink,
|
||||||
]) {
|
]) {
|
||||||
flake8_use_pathlib::rules::replaceable_by_pathlib(checker, call);
|
flake8_use_pathlib::rules::replaceable_by_pathlib(checker, call);
|
||||||
}
|
}
|
||||||
@@ -1285,22 +1284,22 @@ pub(crate) fn expression(expr: &Expr, checker: &Checker) {
|
|||||||
..
|
..
|
||||||
}) => {
|
}) => {
|
||||||
if checker.enabled(Rule::PercentFormatUnsupportedFormatCharacter) {
|
if checker.enabled(Rule::PercentFormatUnsupportedFormatCharacter) {
|
||||||
checker.report_diagnostic(Diagnostic::new(
|
checker.report_diagnostic(
|
||||||
pyflakes::rules::PercentFormatUnsupportedFormatCharacter {
|
pyflakes::rules::PercentFormatUnsupportedFormatCharacter {
|
||||||
char: c,
|
char: c,
|
||||||
},
|
},
|
||||||
location,
|
location,
|
||||||
));
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
if checker.enabled(Rule::PercentFormatInvalidFormat) {
|
if checker.enabled(Rule::PercentFormatInvalidFormat) {
|
||||||
checker.report_diagnostic(Diagnostic::new(
|
checker.report_diagnostic(
|
||||||
pyflakes::rules::PercentFormatInvalidFormat {
|
pyflakes::rules::PercentFormatInvalidFormat {
|
||||||
message: e.to_string(),
|
message: e.to_string(),
|
||||||
},
|
},
|
||||||
location,
|
location,
|
||||||
));
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(summary) => {
|
Ok(summary) => {
|
||||||
@@ -1364,13 +1363,7 @@ pub(crate) fn expression(expr: &Expr, checker: &Checker) {
|
|||||||
op: Operator::Add, ..
|
op: Operator::Add, ..
|
||||||
}) => {
|
}) => {
|
||||||
if checker.enabled(Rule::ExplicitStringConcatenation) {
|
if checker.enabled(Rule::ExplicitStringConcatenation) {
|
||||||
if let Some(diagnostic) = flake8_implicit_str_concat::rules::explicit(
|
flake8_implicit_str_concat::rules::explicit(checker, expr);
|
||||||
expr,
|
|
||||||
checker.locator,
|
|
||||||
checker.settings,
|
|
||||||
) {
|
|
||||||
checker.report_diagnostic(diagnostic);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if checker.enabled(Rule::CollectionLiteralConcatenation) {
|
if checker.enabled(Rule::CollectionLiteralConcatenation) {
|
||||||
ruff::rules::collection_literal_concatenation(checker, expr);
|
ruff::rules::collection_literal_concatenation(checker, expr);
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
use ruff_diagnostics::Diagnostic;
|
|
||||||
use ruff_python_ast::helpers;
|
use ruff_python_ast::helpers;
|
||||||
use ruff_python_ast::types::Node;
|
use ruff_python_ast::types::Node;
|
||||||
use ruff_python_ast::{self as ast, Expr, Stmt};
|
use ruff_python_ast::{self as ast, Expr, Stmt};
|
||||||
@@ -39,12 +38,12 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
|
|||||||
if !checker.semantic.scope_id.is_global() {
|
if !checker.semantic.scope_id.is_global() {
|
||||||
for name in names {
|
for name in names {
|
||||||
if checker.semantic.nonlocal(name).is_none() {
|
if checker.semantic.nonlocal(name).is_none() {
|
||||||
checker.report_diagnostic(Diagnostic::new(
|
checker.report_diagnostic(
|
||||||
pylint::rules::NonlocalWithoutBinding {
|
pylint::rules::NonlocalWithoutBinding {
|
||||||
name: name.to_string(),
|
name: name.to_string(),
|
||||||
},
|
},
|
||||||
name.range(),
|
name.range(),
|
||||||
));
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -55,22 +54,20 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
|
|||||||
}
|
}
|
||||||
Stmt::Break(_) => {
|
Stmt::Break(_) => {
|
||||||
if checker.enabled(Rule::BreakOutsideLoop) {
|
if checker.enabled(Rule::BreakOutsideLoop) {
|
||||||
if let Some(diagnostic) = pyflakes::rules::break_outside_loop(
|
pyflakes::rules::break_outside_loop(
|
||||||
|
checker,
|
||||||
stmt,
|
stmt,
|
||||||
&mut checker.semantic.current_statements().skip(1),
|
&mut checker.semantic.current_statements().skip(1),
|
||||||
) {
|
);
|
||||||
checker.report_diagnostic(diagnostic);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Stmt::Continue(_) => {
|
Stmt::Continue(_) => {
|
||||||
if checker.enabled(Rule::ContinueOutsideLoop) {
|
if checker.enabled(Rule::ContinueOutsideLoop) {
|
||||||
if let Some(diagnostic) = pyflakes::rules::continue_outside_loop(
|
pyflakes::rules::continue_outside_loop(
|
||||||
|
checker,
|
||||||
stmt,
|
stmt,
|
||||||
&mut checker.semantic.current_statements().skip(1),
|
&mut checker.semantic.current_statements().skip(1),
|
||||||
) {
|
);
|
||||||
checker.report_diagnostic(diagnostic);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Stmt::FunctionDef(
|
Stmt::FunctionDef(
|
||||||
@@ -98,9 +95,7 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
|
|||||||
fastapi::rules::fastapi_unused_path_parameter(checker, function_def);
|
fastapi::rules::fastapi_unused_path_parameter(checker, function_def);
|
||||||
}
|
}
|
||||||
if checker.enabled(Rule::AmbiguousFunctionName) {
|
if checker.enabled(Rule::AmbiguousFunctionName) {
|
||||||
if let Some(diagnostic) = pycodestyle::rules::ambiguous_function_name(name) {
|
pycodestyle::rules::ambiguous_function_name(checker, name);
|
||||||
checker.report_diagnostic(diagnostic);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if checker.enabled(Rule::InvalidBoolReturnType) {
|
if checker.enabled(Rule::InvalidBoolReturnType) {
|
||||||
pylint::rules::invalid_bool_return(checker, function_def);
|
pylint::rules::invalid_bool_return(checker, function_def);
|
||||||
@@ -121,15 +116,14 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
|
|||||||
pylint::rules::invalid_str_return(checker, function_def);
|
pylint::rules::invalid_str_return(checker, function_def);
|
||||||
}
|
}
|
||||||
if checker.enabled(Rule::InvalidFunctionName) {
|
if checker.enabled(Rule::InvalidFunctionName) {
|
||||||
if let Some(diagnostic) = pep8_naming::rules::invalid_function_name(
|
pep8_naming::rules::invalid_function_name(
|
||||||
|
checker,
|
||||||
stmt,
|
stmt,
|
||||||
name,
|
name,
|
||||||
decorator_list,
|
decorator_list,
|
||||||
&checker.settings.pep8_naming.ignore_names,
|
&checker.settings.pep8_naming.ignore_names,
|
||||||
&checker.semantic,
|
&checker.semantic,
|
||||||
) {
|
);
|
||||||
checker.report_diagnostic(diagnostic);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if checker.source_type.is_stub() {
|
if checker.source_type.is_stub() {
|
||||||
if checker.enabled(Rule::PassStatementStubBody) {
|
if checker.enabled(Rule::PassStatementStubBody) {
|
||||||
@@ -179,14 +173,13 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
|
|||||||
flake8_pyi::rules::pep_484_positional_parameter(checker, function_def);
|
flake8_pyi::rules::pep_484_positional_parameter(checker, function_def);
|
||||||
}
|
}
|
||||||
if checker.enabled(Rule::DunderFunctionName) {
|
if checker.enabled(Rule::DunderFunctionName) {
|
||||||
if let Some(diagnostic) = pep8_naming::rules::dunder_function_name(
|
pep8_naming::rules::dunder_function_name(
|
||||||
|
checker,
|
||||||
checker.semantic.current_scope(),
|
checker.semantic.current_scope(),
|
||||||
stmt,
|
stmt,
|
||||||
name,
|
name,
|
||||||
&checker.settings.pep8_naming.ignore_names,
|
&checker.settings.pep8_naming.ignore_names,
|
||||||
) {
|
);
|
||||||
checker.report_diagnostic(diagnostic);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if checker.enabled(Rule::GlobalStatement) {
|
if checker.enabled(Rule::GlobalStatement) {
|
||||||
pylint::rules::global_statement(checker, name);
|
pylint::rules::global_statement(checker, name);
|
||||||
@@ -231,14 +224,13 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
if checker.enabled(Rule::ComplexStructure) {
|
if checker.enabled(Rule::ComplexStructure) {
|
||||||
if let Some(diagnostic) = mccabe::rules::function_is_too_complex(
|
mccabe::rules::function_is_too_complex(
|
||||||
|
checker,
|
||||||
stmt,
|
stmt,
|
||||||
name,
|
name,
|
||||||
body,
|
body,
|
||||||
checker.settings.mccabe.max_complexity,
|
checker.settings.mccabe.max_complexity,
|
||||||
) {
|
);
|
||||||
checker.report_diagnostic(diagnostic);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if checker.enabled(Rule::HardcodedPasswordDefault) {
|
if checker.enabled(Rule::HardcodedPasswordDefault) {
|
||||||
flake8_bandit::rules::hardcoded_password_default(checker, parameters);
|
flake8_bandit::rules::hardcoded_password_default(checker, parameters);
|
||||||
@@ -258,31 +250,28 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
|
|||||||
pylint::rules::too_many_positional_arguments(checker, function_def);
|
pylint::rules::too_many_positional_arguments(checker, function_def);
|
||||||
}
|
}
|
||||||
if checker.enabled(Rule::TooManyReturnStatements) {
|
if checker.enabled(Rule::TooManyReturnStatements) {
|
||||||
if let Some(diagnostic) = pylint::rules::too_many_return_statements(
|
pylint::rules::too_many_return_statements(
|
||||||
|
checker,
|
||||||
stmt,
|
stmt,
|
||||||
body,
|
body,
|
||||||
checker.settings.pylint.max_returns,
|
checker.settings.pylint.max_returns,
|
||||||
) {
|
);
|
||||||
checker.report_diagnostic(diagnostic);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if checker.enabled(Rule::TooManyBranches) {
|
if checker.enabled(Rule::TooManyBranches) {
|
||||||
if let Some(diagnostic) = pylint::rules::too_many_branches(
|
pylint::rules::too_many_branches(
|
||||||
|
checker,
|
||||||
stmt,
|
stmt,
|
||||||
body,
|
body,
|
||||||
checker.settings.pylint.max_branches,
|
checker.settings.pylint.max_branches,
|
||||||
) {
|
);
|
||||||
checker.report_diagnostic(diagnostic);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if checker.enabled(Rule::TooManyStatements) {
|
if checker.enabled(Rule::TooManyStatements) {
|
||||||
if let Some(diagnostic) = pylint::rules::too_many_statements(
|
pylint::rules::too_many_statements(
|
||||||
|
checker,
|
||||||
stmt,
|
stmt,
|
||||||
body,
|
body,
|
||||||
checker.settings.pylint.max_statements,
|
checker.settings.pylint.max_statements,
|
||||||
) {
|
);
|
||||||
checker.report_diagnostic(diagnostic);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if checker.any_enabled(&[
|
if checker.any_enabled(&[
|
||||||
Rule::PytestFixtureIncorrectParenthesesStyle,
|
Rule::PytestFixtureIncorrectParenthesesStyle,
|
||||||
@@ -439,6 +428,9 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
|
|||||||
if checker.enabled(Rule::UselessObjectInheritance) {
|
if checker.enabled(Rule::UselessObjectInheritance) {
|
||||||
pyupgrade::rules::useless_object_inheritance(checker, class_def);
|
pyupgrade::rules::useless_object_inheritance(checker, class_def);
|
||||||
}
|
}
|
||||||
|
if checker.enabled(Rule::UselessClassMetaclassType) {
|
||||||
|
pyupgrade::rules::useless_class_metaclass_type(checker, class_def);
|
||||||
|
}
|
||||||
if checker.enabled(Rule::ReplaceStrEnum) {
|
if checker.enabled(Rule::ReplaceStrEnum) {
|
||||||
if checker.target_version() >= PythonVersion::PY311 {
|
if checker.target_version() >= PythonVersion::PY311 {
|
||||||
pyupgrade::rules::replace_str_enum(checker, class_def);
|
pyupgrade::rules::replace_str_enum(checker, class_def);
|
||||||
@@ -448,28 +440,24 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
|
|||||||
pyupgrade::rules::unnecessary_class_parentheses(checker, class_def);
|
pyupgrade::rules::unnecessary_class_parentheses(checker, class_def);
|
||||||
}
|
}
|
||||||
if checker.enabled(Rule::AmbiguousClassName) {
|
if checker.enabled(Rule::AmbiguousClassName) {
|
||||||
if let Some(diagnostic) = pycodestyle::rules::ambiguous_class_name(name) {
|
pycodestyle::rules::ambiguous_class_name(checker, name);
|
||||||
checker.report_diagnostic(diagnostic);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if checker.enabled(Rule::InvalidClassName) {
|
if checker.enabled(Rule::InvalidClassName) {
|
||||||
if let Some(diagnostic) = pep8_naming::rules::invalid_class_name(
|
pep8_naming::rules::invalid_class_name(
|
||||||
|
checker,
|
||||||
stmt,
|
stmt,
|
||||||
name,
|
name,
|
||||||
&checker.settings.pep8_naming.ignore_names,
|
&checker.settings.pep8_naming.ignore_names,
|
||||||
) {
|
);
|
||||||
checker.report_diagnostic(diagnostic);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if checker.enabled(Rule::ErrorSuffixOnExceptionName) {
|
if checker.enabled(Rule::ErrorSuffixOnExceptionName) {
|
||||||
if let Some(diagnostic) = pep8_naming::rules::error_suffix_on_exception_name(
|
pep8_naming::rules::error_suffix_on_exception_name(
|
||||||
|
checker,
|
||||||
stmt,
|
stmt,
|
||||||
arguments.as_deref(),
|
arguments.as_deref(),
|
||||||
name,
|
name,
|
||||||
&checker.settings.pep8_naming.ignore_names,
|
&checker.settings.pep8_naming.ignore_names,
|
||||||
) {
|
);
|
||||||
checker.report_diagnostic(diagnostic);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if !checker.source_type.is_stub() {
|
if !checker.source_type.is_stub() {
|
||||||
if checker.any_enabled(&[
|
if checker.any_enabled(&[
|
||||||
@@ -608,11 +596,7 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if checker.enabled(Rule::Debugger) {
|
if checker.enabled(Rule::Debugger) {
|
||||||
if let Some(diagnostic) =
|
flake8_debugger::rules::debugger_import(checker, stmt, None, &alias.name);
|
||||||
flake8_debugger::rules::debugger_import(stmt, None, &alias.name)
|
|
||||||
{
|
|
||||||
checker.report_diagnostic(diagnostic);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if checker.enabled(Rule::BannedApi) {
|
if checker.enabled(Rule::BannedApi) {
|
||||||
flake8_tidy_imports::rules::banned_api(
|
flake8_tidy_imports::rules::banned_api(
|
||||||
@@ -635,94 +619,74 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
|
|||||||
pylint::rules::manual_from_import(checker, stmt, alias, names);
|
pylint::rules::manual_from_import(checker, stmt, alias, names);
|
||||||
}
|
}
|
||||||
if checker.enabled(Rule::ImportSelf) {
|
if checker.enabled(Rule::ImportSelf) {
|
||||||
if let Some(diagnostic) =
|
pylint::rules::import_self(checker, alias, checker.module.qualified_name());
|
||||||
pylint::rules::import_self(alias, checker.module.qualified_name())
|
|
||||||
{
|
|
||||||
checker.report_diagnostic(diagnostic);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if let Some(asname) = &alias.asname {
|
if let Some(asname) = &alias.asname {
|
||||||
let name = alias.name.split('.').next_back().unwrap();
|
let name = alias.name.split('.').next_back().unwrap();
|
||||||
if checker.enabled(Rule::ConstantImportedAsNonConstant) {
|
if checker.enabled(Rule::ConstantImportedAsNonConstant) {
|
||||||
if let Some(diagnostic) =
|
pep8_naming::rules::constant_imported_as_non_constant(
|
||||||
pep8_naming::rules::constant_imported_as_non_constant(
|
checker,
|
||||||
name,
|
|
||||||
asname,
|
|
||||||
alias,
|
|
||||||
stmt,
|
|
||||||
&checker.settings.pep8_naming.ignore_names,
|
|
||||||
)
|
|
||||||
{
|
|
||||||
checker.report_diagnostic(diagnostic);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if checker.enabled(Rule::LowercaseImportedAsNonLowercase) {
|
|
||||||
if let Some(diagnostic) =
|
|
||||||
pep8_naming::rules::lowercase_imported_as_non_lowercase(
|
|
||||||
name,
|
|
||||||
asname,
|
|
||||||
alias,
|
|
||||||
stmt,
|
|
||||||
&checker.settings.pep8_naming.ignore_names,
|
|
||||||
)
|
|
||||||
{
|
|
||||||
checker.report_diagnostic(diagnostic);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if checker.enabled(Rule::CamelcaseImportedAsLowercase) {
|
|
||||||
if let Some(diagnostic) =
|
|
||||||
pep8_naming::rules::camelcase_imported_as_lowercase(
|
|
||||||
name,
|
|
||||||
asname,
|
|
||||||
alias,
|
|
||||||
stmt,
|
|
||||||
&checker.settings.pep8_naming.ignore_names,
|
|
||||||
)
|
|
||||||
{
|
|
||||||
checker.report_diagnostic(diagnostic);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if checker.enabled(Rule::CamelcaseImportedAsConstant) {
|
|
||||||
if let Some(diagnostic) = pep8_naming::rules::camelcase_imported_as_constant(
|
|
||||||
name,
|
name,
|
||||||
asname,
|
asname,
|
||||||
alias,
|
alias,
|
||||||
stmt,
|
stmt,
|
||||||
&checker.settings.pep8_naming.ignore_names,
|
&checker.settings.pep8_naming.ignore_names,
|
||||||
) {
|
);
|
||||||
checker.report_diagnostic(diagnostic);
|
}
|
||||||
}
|
if checker.enabled(Rule::LowercaseImportedAsNonLowercase) {
|
||||||
|
pep8_naming::rules::lowercase_imported_as_non_lowercase(
|
||||||
|
checker,
|
||||||
|
name,
|
||||||
|
asname,
|
||||||
|
alias,
|
||||||
|
stmt,
|
||||||
|
&checker.settings.pep8_naming.ignore_names,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if checker.enabled(Rule::CamelcaseImportedAsLowercase) {
|
||||||
|
pep8_naming::rules::camelcase_imported_as_lowercase(
|
||||||
|
checker,
|
||||||
|
name,
|
||||||
|
asname,
|
||||||
|
alias,
|
||||||
|
stmt,
|
||||||
|
&checker.settings.pep8_naming.ignore_names,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if checker.enabled(Rule::CamelcaseImportedAsConstant) {
|
||||||
|
pep8_naming::rules::camelcase_imported_as_constant(
|
||||||
|
checker,
|
||||||
|
name,
|
||||||
|
asname,
|
||||||
|
alias,
|
||||||
|
stmt,
|
||||||
|
&checker.settings.pep8_naming.ignore_names,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
if checker.enabled(Rule::CamelcaseImportedAsAcronym) {
|
if checker.enabled(Rule::CamelcaseImportedAsAcronym) {
|
||||||
if let Some(diagnostic) = pep8_naming::rules::camelcase_imported_as_acronym(
|
pep8_naming::rules::camelcase_imported_as_acronym(
|
||||||
name, asname, alias, stmt, checker,
|
name, asname, alias, stmt, checker,
|
||||||
) {
|
);
|
||||||
checker.report_diagnostic(diagnostic);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if checker.enabled(Rule::BannedImportAlias) {
|
if checker.enabled(Rule::BannedImportAlias) {
|
||||||
if let Some(asname) = &alias.asname {
|
if let Some(asname) = &alias.asname {
|
||||||
if let Some(diagnostic) =
|
flake8_import_conventions::rules::banned_import_alias(
|
||||||
flake8_import_conventions::rules::banned_import_alias(
|
checker,
|
||||||
stmt,
|
stmt,
|
||||||
&alias.name,
|
&alias.name,
|
||||||
asname,
|
asname,
|
||||||
&checker.settings.flake8_import_conventions.banned_aliases,
|
&checker.settings.flake8_import_conventions.banned_aliases,
|
||||||
)
|
);
|
||||||
{
|
|
||||||
checker.report_diagnostic(diagnostic);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if checker.enabled(Rule::PytestIncorrectPytestImport) {
|
if checker.enabled(Rule::PytestIncorrectPytestImport) {
|
||||||
if let Some(diagnostic) = flake8_pytest_style::rules::import(
|
flake8_pytest_style::rules::import(
|
||||||
|
checker,
|
||||||
stmt,
|
stmt,
|
||||||
&alias.name,
|
&alias.name,
|
||||||
alias.asname.as_deref(),
|
alias.asname.as_deref(),
|
||||||
) {
|
);
|
||||||
checker.report_diagnostic(diagnostic);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if checker.enabled(Rule::BuiltinImportShadowing) {
|
if checker.enabled(Rule::BuiltinImportShadowing) {
|
||||||
flake8_builtins::rules::builtin_import_shadowing(checker, alias);
|
flake8_builtins::rules::builtin_import_shadowing(checker, alias);
|
||||||
@@ -834,11 +798,7 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if checker.enabled(Rule::PytestIncorrectPytestImport) {
|
if checker.enabled(Rule::PytestIncorrectPytestImport) {
|
||||||
if let Some(diagnostic) =
|
flake8_pytest_style::rules::import_from(checker, stmt, module, level);
|
||||||
flake8_pytest_style::rules::import_from(stmt, module, level)
|
|
||||||
{
|
|
||||||
checker.report_diagnostic(diagnostic);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if checker.source_type.is_stub() {
|
if checker.source_type.is_stub() {
|
||||||
if checker.enabled(Rule::FutureAnnotationsInStub) {
|
if checker.enabled(Rule::FutureAnnotationsInStub) {
|
||||||
@@ -853,119 +813,98 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
|
|||||||
} else if &alias.name == "*" {
|
} else if &alias.name == "*" {
|
||||||
if checker.enabled(Rule::UndefinedLocalWithNestedImportStarUsage) {
|
if checker.enabled(Rule::UndefinedLocalWithNestedImportStarUsage) {
|
||||||
if !matches!(checker.semantic.current_scope().kind, ScopeKind::Module) {
|
if !matches!(checker.semantic.current_scope().kind, ScopeKind::Module) {
|
||||||
checker.report_diagnostic(Diagnostic::new(
|
checker.report_diagnostic(
|
||||||
pyflakes::rules::UndefinedLocalWithNestedImportStarUsage {
|
pyflakes::rules::UndefinedLocalWithNestedImportStarUsage {
|
||||||
name: helpers::format_import_from(level, module).to_string(),
|
name: helpers::format_import_from(level, module).to_string(),
|
||||||
},
|
},
|
||||||
stmt.range(),
|
stmt.range(),
|
||||||
));
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if checker.enabled(Rule::UndefinedLocalWithImportStar) {
|
if checker.enabled(Rule::UndefinedLocalWithImportStar) {
|
||||||
checker.report_diagnostic(Diagnostic::new(
|
checker.report_diagnostic(
|
||||||
pyflakes::rules::UndefinedLocalWithImportStar {
|
pyflakes::rules::UndefinedLocalWithImportStar {
|
||||||
name: helpers::format_import_from(level, module).to_string(),
|
name: helpers::format_import_from(level, module).to_string(),
|
||||||
},
|
},
|
||||||
stmt.range(),
|
stmt.range(),
|
||||||
));
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if checker.enabled(Rule::RelativeImports) {
|
if checker.enabled(Rule::RelativeImports) {
|
||||||
if let Some(diagnostic) = flake8_tidy_imports::rules::banned_relative_import(
|
flake8_tidy_imports::rules::banned_relative_import(
|
||||||
checker,
|
checker,
|
||||||
stmt,
|
stmt,
|
||||||
level,
|
level,
|
||||||
module,
|
module,
|
||||||
checker.module.qualified_name(),
|
checker.module.qualified_name(),
|
||||||
checker.settings.flake8_tidy_imports.ban_relative_imports,
|
checker.settings.flake8_tidy_imports.ban_relative_imports,
|
||||||
) {
|
);
|
||||||
checker.report_diagnostic(diagnostic);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if checker.enabled(Rule::Debugger) {
|
if checker.enabled(Rule::Debugger) {
|
||||||
if let Some(diagnostic) =
|
flake8_debugger::rules::debugger_import(checker, stmt, module, &alias.name);
|
||||||
flake8_debugger::rules::debugger_import(stmt, module, &alias.name)
|
|
||||||
{
|
|
||||||
checker.report_diagnostic(diagnostic);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if checker.enabled(Rule::BannedImportAlias) {
|
if checker.enabled(Rule::BannedImportAlias) {
|
||||||
if let Some(asname) = &alias.asname {
|
if let Some(asname) = &alias.asname {
|
||||||
let qualified_name =
|
let qualified_name =
|
||||||
helpers::format_import_from_member(level, module, &alias.name);
|
helpers::format_import_from_member(level, module, &alias.name);
|
||||||
if let Some(diagnostic) =
|
flake8_import_conventions::rules::banned_import_alias(
|
||||||
flake8_import_conventions::rules::banned_import_alias(
|
checker,
|
||||||
stmt,
|
stmt,
|
||||||
&qualified_name,
|
&qualified_name,
|
||||||
asname,
|
asname,
|
||||||
&checker.settings.flake8_import_conventions.banned_aliases,
|
&checker.settings.flake8_import_conventions.banned_aliases,
|
||||||
)
|
);
|
||||||
{
|
|
||||||
checker.report_diagnostic(diagnostic);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some(asname) = &alias.asname {
|
if let Some(asname) = &alias.asname {
|
||||||
if checker.enabled(Rule::ConstantImportedAsNonConstant) {
|
if checker.enabled(Rule::ConstantImportedAsNonConstant) {
|
||||||
if let Some(diagnostic) =
|
pep8_naming::rules::constant_imported_as_non_constant(
|
||||||
pep8_naming::rules::constant_imported_as_non_constant(
|
checker,
|
||||||
&alias.name,
|
|
||||||
asname,
|
|
||||||
alias,
|
|
||||||
stmt,
|
|
||||||
&checker.settings.pep8_naming.ignore_names,
|
|
||||||
)
|
|
||||||
{
|
|
||||||
checker.report_diagnostic(diagnostic);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if checker.enabled(Rule::LowercaseImportedAsNonLowercase) {
|
|
||||||
if let Some(diagnostic) =
|
|
||||||
pep8_naming::rules::lowercase_imported_as_non_lowercase(
|
|
||||||
&alias.name,
|
|
||||||
asname,
|
|
||||||
alias,
|
|
||||||
stmt,
|
|
||||||
&checker.settings.pep8_naming.ignore_names,
|
|
||||||
)
|
|
||||||
{
|
|
||||||
checker.report_diagnostic(diagnostic);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if checker.enabled(Rule::CamelcaseImportedAsLowercase) {
|
|
||||||
if let Some(diagnostic) =
|
|
||||||
pep8_naming::rules::camelcase_imported_as_lowercase(
|
|
||||||
&alias.name,
|
|
||||||
asname,
|
|
||||||
alias,
|
|
||||||
stmt,
|
|
||||||
&checker.settings.pep8_naming.ignore_names,
|
|
||||||
)
|
|
||||||
{
|
|
||||||
checker.report_diagnostic(diagnostic);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if checker.enabled(Rule::CamelcaseImportedAsConstant) {
|
|
||||||
if let Some(diagnostic) = pep8_naming::rules::camelcase_imported_as_constant(
|
|
||||||
&alias.name,
|
&alias.name,
|
||||||
asname,
|
asname,
|
||||||
alias,
|
alias,
|
||||||
stmt,
|
stmt,
|
||||||
&checker.settings.pep8_naming.ignore_names,
|
&checker.settings.pep8_naming.ignore_names,
|
||||||
) {
|
);
|
||||||
checker.report_diagnostic(diagnostic);
|
}
|
||||||
}
|
if checker.enabled(Rule::LowercaseImportedAsNonLowercase) {
|
||||||
|
pep8_naming::rules::lowercase_imported_as_non_lowercase(
|
||||||
|
checker,
|
||||||
|
&alias.name,
|
||||||
|
asname,
|
||||||
|
alias,
|
||||||
|
stmt,
|
||||||
|
&checker.settings.pep8_naming.ignore_names,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if checker.enabled(Rule::CamelcaseImportedAsLowercase) {
|
||||||
|
pep8_naming::rules::camelcase_imported_as_lowercase(
|
||||||
|
checker,
|
||||||
|
&alias.name,
|
||||||
|
asname,
|
||||||
|
alias,
|
||||||
|
stmt,
|
||||||
|
&checker.settings.pep8_naming.ignore_names,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if checker.enabled(Rule::CamelcaseImportedAsConstant) {
|
||||||
|
pep8_naming::rules::camelcase_imported_as_constant(
|
||||||
|
checker,
|
||||||
|
&alias.name,
|
||||||
|
asname,
|
||||||
|
alias,
|
||||||
|
stmt,
|
||||||
|
&checker.settings.pep8_naming.ignore_names,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
if checker.enabled(Rule::CamelcaseImportedAsAcronym) {
|
if checker.enabled(Rule::CamelcaseImportedAsAcronym) {
|
||||||
if let Some(diagnostic) = pep8_naming::rules::camelcase_imported_as_acronym(
|
pep8_naming::rules::camelcase_imported_as_acronym(
|
||||||
&alias.name,
|
&alias.name,
|
||||||
asname,
|
asname,
|
||||||
alias,
|
alias,
|
||||||
stmt,
|
stmt,
|
||||||
checker,
|
checker,
|
||||||
) {
|
);
|
||||||
checker.report_diagnostic(diagnostic);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if !checker.source_type.is_stub() {
|
if !checker.source_type.is_stub() {
|
||||||
if checker.enabled(Rule::UselessImportAlias) {
|
if checker.enabled(Rule::UselessImportAlias) {
|
||||||
@@ -978,23 +917,21 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if checker.enabled(Rule::ImportSelf) {
|
if checker.enabled(Rule::ImportSelf) {
|
||||||
if let Some(diagnostic) = pylint::rules::import_from_self(
|
pylint::rules::import_from_self(
|
||||||
|
checker,
|
||||||
level,
|
level,
|
||||||
module,
|
module,
|
||||||
names,
|
names,
|
||||||
checker.module.qualified_name(),
|
checker.module.qualified_name(),
|
||||||
) {
|
);
|
||||||
checker.report_diagnostic(diagnostic);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if checker.enabled(Rule::BannedImportFrom) {
|
if checker.enabled(Rule::BannedImportFrom) {
|
||||||
if let Some(diagnostic) = flake8_import_conventions::rules::banned_import_from(
|
flake8_import_conventions::rules::banned_import_from(
|
||||||
|
checker,
|
||||||
stmt,
|
stmt,
|
||||||
&helpers::format_import_from(level, module),
|
&helpers::format_import_from(level, module),
|
||||||
&checker.settings.flake8_import_conventions.banned_from,
|
&checker.settings.flake8_import_conventions.banned_from,
|
||||||
) {
|
);
|
||||||
checker.report_diagnostic(diagnostic);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if checker.enabled(Rule::ByteStringUsage) {
|
if checker.enabled(Rule::ByteStringUsage) {
|
||||||
flake8_pyi::rules::bytestring_import(checker, import_from);
|
flake8_pyi::rules::bytestring_import(checker, import_from);
|
||||||
@@ -1209,7 +1146,7 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
|
|||||||
) => {
|
) => {
|
||||||
if !checker.semantic.in_type_checking_block() {
|
if !checker.semantic.in_type_checking_block() {
|
||||||
if checker.enabled(Rule::Assert) {
|
if checker.enabled(Rule::Assert) {
|
||||||
checker.report_diagnostic(flake8_bandit::rules::assert_used(stmt));
|
flake8_bandit::rules::assert_used(checker, stmt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if checker.enabled(Rule::AssertTuple) {
|
if checker.enabled(Rule::AssertTuple) {
|
||||||
@@ -1406,11 +1343,7 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if checker.enabled(Rule::DefaultExceptNotLast) {
|
if checker.enabled(Rule::DefaultExceptNotLast) {
|
||||||
if let Some(diagnostic) =
|
pyflakes::rules::default_except_not_last(checker, handlers, checker.locator);
|
||||||
pyflakes::rules::default_except_not_last(handlers, checker.locator)
|
|
||||||
{
|
|
||||||
checker.report_diagnostic(diagnostic);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if checker.any_enabled(&[
|
if checker.any_enabled(&[
|
||||||
Rule::DuplicateHandlerException,
|
Rule::DuplicateHandlerException,
|
||||||
@@ -1505,9 +1438,7 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
if checker.enabled(Rule::PandasDfVariableName) {
|
if checker.enabled(Rule::PandasDfVariableName) {
|
||||||
if let Some(diagnostic) = pandas_vet::rules::assignment_to_df(targets) {
|
pandas_vet::rules::assignment_to_df(checker, targets);
|
||||||
checker.report_diagnostic(diagnostic);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if checker
|
if checker
|
||||||
.settings
|
.settings
|
||||||
@@ -1701,11 +1632,7 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
|
|||||||
pylint::rules::named_expr_without_context(checker, value);
|
pylint::rules::named_expr_without_context(checker, value);
|
||||||
}
|
}
|
||||||
if checker.enabled(Rule::AsyncioDanglingTask) {
|
if checker.enabled(Rule::AsyncioDanglingTask) {
|
||||||
if let Some(diagnostic) =
|
ruff::rules::asyncio_dangling_task(checker, value, checker.semantic());
|
||||||
ruff::rules::asyncio_dangling_task(value, checker.semantic())
|
|
||||||
{
|
|
||||||
checker.report_diagnostic(diagnostic);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if checker.enabled(Rule::RepeatedAppend) {
|
if checker.enabled(Rule::RepeatedAppend) {
|
||||||
refurb::rules::repeated_append(checker, stmt);
|
refurb::rules::repeated_append(checker, stmt);
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
use ruff_diagnostics::Diagnostic;
|
|
||||||
use ruff_python_semantic::Exceptions;
|
use ruff_python_semantic::Exceptions;
|
||||||
use ruff_python_stdlib::builtins::version_builtin_was_added;
|
use ruff_python_stdlib::builtins::version_builtin_was_added;
|
||||||
|
|
||||||
@@ -15,12 +14,12 @@ pub(crate) fn unresolved_references(checker: &Checker) {
|
|||||||
for reference in checker.semantic.unresolved_references() {
|
for reference in checker.semantic.unresolved_references() {
|
||||||
if reference.is_wildcard_import() {
|
if reference.is_wildcard_import() {
|
||||||
if checker.enabled(Rule::UndefinedLocalWithImportStarUsage) {
|
if checker.enabled(Rule::UndefinedLocalWithImportStarUsage) {
|
||||||
checker.report_diagnostic(Diagnostic::new(
|
checker.report_diagnostic(
|
||||||
pyflakes::rules::UndefinedLocalWithImportStarUsage {
|
pyflakes::rules::UndefinedLocalWithImportStarUsage {
|
||||||
name: reference.name(checker.source()).to_string(),
|
name: reference.name(checker.source()).to_string(),
|
||||||
},
|
},
|
||||||
reference.range(),
|
reference.range(),
|
||||||
));
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if checker.enabled(Rule::UndefinedName) {
|
if checker.enabled(Rule::UndefinedName) {
|
||||||
@@ -42,13 +41,13 @@ pub(crate) fn unresolved_references(checker: &Checker) {
|
|||||||
|
|
||||||
let symbol_name = reference.name(checker.source());
|
let symbol_name = reference.name(checker.source());
|
||||||
|
|
||||||
checker.report_diagnostic(Diagnostic::new(
|
checker.report_diagnostic(
|
||||||
pyflakes::rules::UndefinedName {
|
pyflakes::rules::UndefinedName {
|
||||||
name: symbol_name.to_string(),
|
name: symbol_name.to_string(),
|
||||||
minor_version_builtin_added: version_builtin_was_added(symbol_name),
|
minor_version_builtin_added: version_builtin_was_added(symbol_name),
|
||||||
},
|
},
|
||||||
reference.range(),
|
reference.range(),
|
||||||
));
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,12 +26,9 @@ use std::path::Path;
|
|||||||
|
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use log::debug;
|
use log::debug;
|
||||||
use ruff_python_parser::semantic_errors::{
|
|
||||||
SemanticSyntaxChecker, SemanticSyntaxContext, SemanticSyntaxError, SemanticSyntaxErrorKind,
|
|
||||||
};
|
|
||||||
use rustc_hash::{FxHashMap, FxHashSet};
|
use rustc_hash::{FxHashMap, FxHashSet};
|
||||||
|
|
||||||
use ruff_diagnostics::{Diagnostic, Edit, IsolationLevel};
|
use ruff_diagnostics::IsolationLevel;
|
||||||
use ruff_notebook::{CellOffsets, NotebookIndex};
|
use ruff_notebook::{CellOffsets, NotebookIndex};
|
||||||
use ruff_python_ast::helpers::{collect_import_from_member, is_docstring_stmt, to_module_path};
|
use ruff_python_ast::helpers::{collect_import_from_member, is_docstring_stmt, to_module_path};
|
||||||
use ruff_python_ast::identifier::Identifier;
|
use ruff_python_ast::identifier::Identifier;
|
||||||
@@ -40,12 +37,15 @@ use ruff_python_ast::str::Quote;
|
|||||||
use ruff_python_ast::visitor::{Visitor, walk_except_handler, walk_pattern};
|
use ruff_python_ast::visitor::{Visitor, walk_except_handler, walk_pattern};
|
||||||
use ruff_python_ast::{
|
use ruff_python_ast::{
|
||||||
self as ast, AnyParameterRef, ArgOrKeyword, Comprehension, ElifElseClause, ExceptHandler, Expr,
|
self as ast, AnyParameterRef, ArgOrKeyword, Comprehension, ElifElseClause, ExceptHandler, Expr,
|
||||||
ExprContext, FStringElement, Keyword, MatchCase, ModModule, Parameter, Parameters, Pattern,
|
ExprContext, InterpolatedStringElement, Keyword, MatchCase, ModModule, Parameter, Parameters,
|
||||||
PythonVersion, Stmt, Suite, UnaryOp,
|
Pattern, PythonVersion, Stmt, Suite, UnaryOp,
|
||||||
};
|
};
|
||||||
use ruff_python_ast::{PySourceType, helpers, str, visitor};
|
use ruff_python_ast::{PySourceType, helpers, str, visitor};
|
||||||
use ruff_python_codegen::{Generator, Stylist};
|
use ruff_python_codegen::{Generator, Stylist};
|
||||||
use ruff_python_index::Indexer;
|
use ruff_python_index::Indexer;
|
||||||
|
use ruff_python_parser::semantic_errors::{
|
||||||
|
SemanticSyntaxChecker, SemanticSyntaxContext, SemanticSyntaxError, SemanticSyntaxErrorKind,
|
||||||
|
};
|
||||||
use ruff_python_parser::typing::{AnnotationKind, ParsedAnnotation, parse_type_annotation};
|
use ruff_python_parser::typing::{AnnotationKind, ParsedAnnotation, parse_type_annotation};
|
||||||
use ruff_python_parser::{ParseError, Parsed, Tokens};
|
use ruff_python_parser::{ParseError, Parsed, Tokens};
|
||||||
use ruff_python_semantic::all::{DunderAllDefinition, DunderAllFlags};
|
use ruff_python_semantic::all::{DunderAllDefinition, DunderAllFlags};
|
||||||
@@ -57,7 +57,7 @@ use ruff_python_semantic::{
|
|||||||
};
|
};
|
||||||
use ruff_python_stdlib::builtins::{MAGIC_GLOBALS, python_builtins};
|
use ruff_python_stdlib::builtins::{MAGIC_GLOBALS, python_builtins};
|
||||||
use ruff_python_trivia::CommentRanges;
|
use ruff_python_trivia::CommentRanges;
|
||||||
use ruff_source_file::{OneIndexed, SourceRow};
|
use ruff_source_file::{OneIndexed, SourceFile, SourceRow};
|
||||||
use ruff_text_size::{Ranged, TextRange, TextSize};
|
use ruff_text_size::{Ranged, TextRange, TextSize};
|
||||||
|
|
||||||
use crate::checkers::ast::annotation::AnnotationContext;
|
use crate::checkers::ast::annotation::AnnotationContext;
|
||||||
@@ -66,13 +66,14 @@ use crate::importer::{ImportRequest, Importer, ResolutionError};
|
|||||||
use crate::noqa::NoqaMapping;
|
use crate::noqa::NoqaMapping;
|
||||||
use crate::package::PackageRoot;
|
use crate::package::PackageRoot;
|
||||||
use crate::preview::{is_semantic_errors_enabled, is_undefined_export_in_dunder_init_enabled};
|
use crate::preview::{is_semantic_errors_enabled, is_undefined_export_in_dunder_init_enabled};
|
||||||
use crate::registry::Rule;
|
use crate::registry::{AsRule, Rule};
|
||||||
use crate::rules::pyflakes::rules::{
|
use crate::rules::pyflakes::rules::{
|
||||||
LateFutureImport, ReturnOutsideFunction, YieldOutsideFunction,
|
LateFutureImport, ReturnOutsideFunction, YieldOutsideFunction,
|
||||||
};
|
};
|
||||||
use crate::rules::pylint::rules::{AwaitOutsideAsync, LoadBeforeGlobalDeclaration};
|
use crate::rules::pylint::rules::{AwaitOutsideAsync, LoadBeforeGlobalDeclaration};
|
||||||
use crate::rules::{flake8_pyi, flake8_type_checking, pyflakes, pyupgrade};
|
use crate::rules::{flake8_pyi, flake8_type_checking, pyflakes, pyupgrade};
|
||||||
use crate::settings::{LinterSettings, TargetVersion, flags};
|
use crate::settings::{LinterSettings, TargetVersion, flags};
|
||||||
|
use crate::{Edit, OldDiagnostic, Violation};
|
||||||
use crate::{Locator, docstrings, noqa};
|
use crate::{Locator, docstrings, noqa};
|
||||||
|
|
||||||
mod analyze;
|
mod analyze;
|
||||||
@@ -223,8 +224,6 @@ pub(crate) struct Checker<'a> {
|
|||||||
visit: deferred::Visit<'a>,
|
visit: deferred::Visit<'a>,
|
||||||
/// A set of deferred nodes to be analyzed after the AST traversal (e.g., `for` loops).
|
/// A set of deferred nodes to be analyzed after the AST traversal (e.g., `for` loops).
|
||||||
analyze: deferred::Analyze,
|
analyze: deferred::Analyze,
|
||||||
/// The cumulative set of diagnostics computed across all lint rules.
|
|
||||||
diagnostics: RefCell<Vec<Diagnostic>>,
|
|
||||||
/// The list of names already seen by flake8-bugbear diagnostics, to avoid duplicate violations.
|
/// The list of names already seen by flake8-bugbear diagnostics, to avoid duplicate violations.
|
||||||
flake8_bugbear_seen: RefCell<FxHashSet<TextRange>>,
|
flake8_bugbear_seen: RefCell<FxHashSet<TextRange>>,
|
||||||
/// The end offset of the last visited statement.
|
/// The end offset of the last visited statement.
|
||||||
@@ -238,6 +237,7 @@ pub(crate) struct Checker<'a> {
|
|||||||
semantic_checker: SemanticSyntaxChecker,
|
semantic_checker: SemanticSyntaxChecker,
|
||||||
/// Errors collected by the `semantic_checker`.
|
/// Errors collected by the `semantic_checker`.
|
||||||
semantic_errors: RefCell<Vec<SemanticSyntaxError>>,
|
semantic_errors: RefCell<Vec<SemanticSyntaxError>>,
|
||||||
|
context: &'a LintContext<'a>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Checker<'a> {
|
impl<'a> Checker<'a> {
|
||||||
@@ -258,6 +258,7 @@ impl<'a> Checker<'a> {
|
|||||||
cell_offsets: Option<&'a CellOffsets>,
|
cell_offsets: Option<&'a CellOffsets>,
|
||||||
notebook_index: Option<&'a NotebookIndex>,
|
notebook_index: Option<&'a NotebookIndex>,
|
||||||
target_version: TargetVersion,
|
target_version: TargetVersion,
|
||||||
|
context: &'a LintContext<'a>,
|
||||||
) -> Checker<'a> {
|
) -> Checker<'a> {
|
||||||
let semantic = SemanticModel::new(&settings.typing_modules, path, module);
|
let semantic = SemanticModel::new(&settings.typing_modules, path, module);
|
||||||
Self {
|
Self {
|
||||||
@@ -278,7 +279,6 @@ impl<'a> Checker<'a> {
|
|||||||
semantic,
|
semantic,
|
||||||
visit: deferred::Visit::default(),
|
visit: deferred::Visit::default(),
|
||||||
analyze: deferred::Analyze::default(),
|
analyze: deferred::Analyze::default(),
|
||||||
diagnostics: RefCell::default(),
|
|
||||||
flake8_bugbear_seen: RefCell::default(),
|
flake8_bugbear_seen: RefCell::default(),
|
||||||
cell_offsets,
|
cell_offsets,
|
||||||
notebook_index,
|
notebook_index,
|
||||||
@@ -287,6 +287,7 @@ impl<'a> Checker<'a> {
|
|||||||
target_version,
|
target_version,
|
||||||
semantic_checker: SemanticSyntaxChecker::new(),
|
semantic_checker: SemanticSyntaxChecker::new(),
|
||||||
semantic_errors: RefCell::default(),
|
semantic_errors: RefCell::default(),
|
||||||
|
context,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -337,6 +338,7 @@ impl<'a> Checker<'a> {
|
|||||||
ast::BytesLiteralFlags::empty().with_quote_style(self.preferred_quote())
|
ast::BytesLiteralFlags::empty().with_quote_style(self.preferred_quote())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO(dylan) add similar method for t-strings
|
||||||
/// Return the default f-string flags a generated `FString` node should use, given where we are
|
/// Return the default f-string flags a generated `FString` node should use, given where we are
|
||||||
/// in the AST.
|
/// in the AST.
|
||||||
pub(crate) fn default_fstring_flags(&self) -> ast::FStringFlags {
|
pub(crate) fn default_fstring_flags(&self) -> ast::FStringFlags {
|
||||||
@@ -379,10 +381,30 @@ impl<'a> Checker<'a> {
|
|||||||
self.indexer.comment_ranges()
|
self.indexer.comment_ranges()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Push a new [`Diagnostic`] to the collection in the [`Checker`]
|
/// Return a [`DiagnosticGuard`] for reporting a diagnostic.
|
||||||
pub(crate) fn report_diagnostic(&self, diagnostic: Diagnostic) {
|
///
|
||||||
let mut diagnostics = self.diagnostics.borrow_mut();
|
/// The guard derefs to a [`Diagnostic`], so it can be used to further modify the diagnostic
|
||||||
diagnostics.push(diagnostic);
|
/// before it is added to the collection in the checker on `Drop`.
|
||||||
|
pub(crate) fn report_diagnostic<'chk, T: Violation>(
|
||||||
|
&'chk self,
|
||||||
|
kind: T,
|
||||||
|
range: TextRange,
|
||||||
|
) -> DiagnosticGuard<'chk, 'a> {
|
||||||
|
self.context.report_diagnostic(kind, range)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return a [`DiagnosticGuard`] for reporting a diagnostic if the corresponding rule is
|
||||||
|
/// enabled.
|
||||||
|
///
|
||||||
|
/// Prefer [`Checker::report_diagnostic`] in general because the conversion from a `Diagnostic`
|
||||||
|
/// to a `Rule` is somewhat expensive.
|
||||||
|
pub(crate) fn report_diagnostic_if_enabled<'chk, T: Violation>(
|
||||||
|
&'chk self,
|
||||||
|
kind: T,
|
||||||
|
range: TextRange,
|
||||||
|
) -> Option<DiagnosticGuard<'chk, 'a>> {
|
||||||
|
self.context
|
||||||
|
.report_diagnostic_if_enabled(kind, range, self.settings)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Adds a [`TextRange`] to the set of ranges of variable names
|
/// Adds a [`TextRange`] to the set of ranges of variable names
|
||||||
@@ -508,9 +530,9 @@ impl<'a> Checker<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Push `diagnostic` if the checker is not in a `@no_type_check` context.
|
/// Push `diagnostic` if the checker is not in a `@no_type_check` context.
|
||||||
pub(crate) fn report_type_diagnostic(&self, diagnostic: Diagnostic) {
|
pub(crate) fn report_type_diagnostic<T: Violation>(&self, kind: T, range: TextRange) {
|
||||||
if !self.semantic.in_no_type_check() {
|
if !self.semantic.in_no_type_check() {
|
||||||
self.report_diagnostic(diagnostic);
|
self.report_diagnostic(kind, range);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -595,7 +617,7 @@ impl SemanticSyntaxContext for Checker<'_> {
|
|||||||
match error.kind {
|
match error.kind {
|
||||||
SemanticSyntaxErrorKind::LateFutureImport => {
|
SemanticSyntaxErrorKind::LateFutureImport => {
|
||||||
if self.settings.rules.enabled(Rule::LateFutureImport) {
|
if self.settings.rules.enabled(Rule::LateFutureImport) {
|
||||||
self.report_diagnostic(Diagnostic::new(LateFutureImport, error.range));
|
self.report_diagnostic(LateFutureImport, error.range);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SemanticSyntaxErrorKind::LoadBeforeGlobalDeclaration { name, start } => {
|
SemanticSyntaxErrorKind::LoadBeforeGlobalDeclaration { name, start } => {
|
||||||
@@ -604,31 +626,28 @@ impl SemanticSyntaxContext for Checker<'_> {
|
|||||||
.rules
|
.rules
|
||||||
.enabled(Rule::LoadBeforeGlobalDeclaration)
|
.enabled(Rule::LoadBeforeGlobalDeclaration)
|
||||||
{
|
{
|
||||||
self.report_diagnostic(Diagnostic::new(
|
self.report_diagnostic(
|
||||||
LoadBeforeGlobalDeclaration {
|
LoadBeforeGlobalDeclaration {
|
||||||
name,
|
name,
|
||||||
row: self.compute_source_row(start),
|
row: self.compute_source_row(start),
|
||||||
},
|
},
|
||||||
error.range,
|
error.range,
|
||||||
));
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SemanticSyntaxErrorKind::YieldOutsideFunction(kind) => {
|
SemanticSyntaxErrorKind::YieldOutsideFunction(kind) => {
|
||||||
if self.settings.rules.enabled(Rule::YieldOutsideFunction) {
|
if self.settings.rules.enabled(Rule::YieldOutsideFunction) {
|
||||||
self.report_diagnostic(Diagnostic::new(
|
self.report_diagnostic(YieldOutsideFunction::new(kind), error.range);
|
||||||
YieldOutsideFunction::new(kind),
|
|
||||||
error.range,
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SemanticSyntaxErrorKind::ReturnOutsideFunction => {
|
SemanticSyntaxErrorKind::ReturnOutsideFunction => {
|
||||||
if self.settings.rules.enabled(Rule::ReturnOutsideFunction) {
|
if self.settings.rules.enabled(Rule::ReturnOutsideFunction) {
|
||||||
self.report_diagnostic(Diagnostic::new(ReturnOutsideFunction, error.range));
|
self.report_diagnostic(ReturnOutsideFunction, error.range);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SemanticSyntaxErrorKind::AwaitOutsideAsyncFunction(_) => {
|
SemanticSyntaxErrorKind::AwaitOutsideAsyncFunction(_) => {
|
||||||
if self.settings.rules.enabled(Rule::AwaitOutsideAsync) {
|
if self.settings.rules.enabled(Rule::AwaitOutsideAsync) {
|
||||||
self.report_diagnostic(Diagnostic::new(AwaitOutsideAsync, error.range));
|
self.report_diagnostic(AwaitOutsideAsync, error.range);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SemanticSyntaxErrorKind::ReboundComprehensionVariable
|
SemanticSyntaxErrorKind::ReboundComprehensionVariable
|
||||||
@@ -1879,6 +1898,10 @@ impl<'a> Visitor<'a> for Checker<'a> {
|
|||||||
self.semantic.flags |= SemanticModelFlags::F_STRING;
|
self.semantic.flags |= SemanticModelFlags::F_STRING;
|
||||||
visitor::walk_expr(self, expr);
|
visitor::walk_expr(self, expr);
|
||||||
}
|
}
|
||||||
|
Expr::TString(_) => {
|
||||||
|
self.semantic.flags |= SemanticModelFlags::T_STRING;
|
||||||
|
visitor::walk_expr(self, expr);
|
||||||
|
}
|
||||||
Expr::Named(ast::ExprNamed {
|
Expr::Named(ast::ExprNamed {
|
||||||
target,
|
target,
|
||||||
value,
|
value,
|
||||||
@@ -1912,6 +1935,7 @@ impl<'a> Visitor<'a> for Checker<'a> {
|
|||||||
}
|
}
|
||||||
Expr::BytesLiteral(bytes_literal) => analyze::string_like(bytes_literal.into(), self),
|
Expr::BytesLiteral(bytes_literal) => analyze::string_like(bytes_literal.into(), self),
|
||||||
Expr::FString(f_string) => analyze::string_like(f_string.into(), self),
|
Expr::FString(f_string) => analyze::string_like(f_string.into(), self),
|
||||||
|
Expr::TString(t_string) => analyze::string_like(t_string.into(), self),
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2101,12 +2125,15 @@ impl<'a> Visitor<'a> for Checker<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_f_string_element(&mut self, f_string_element: &'a FStringElement) {
|
fn visit_interpolated_string_element(
|
||||||
|
&mut self,
|
||||||
|
interpolated_string_element: &'a InterpolatedStringElement,
|
||||||
|
) {
|
||||||
let snapshot = self.semantic.flags;
|
let snapshot = self.semantic.flags;
|
||||||
if f_string_element.is_expression() {
|
if interpolated_string_element.is_interpolation() {
|
||||||
self.semantic.flags |= SemanticModelFlags::F_STRING_REPLACEMENT_FIELD;
|
self.semantic.flags |= SemanticModelFlags::INTERPOLATED_STRING_REPLACEMENT_FIELD;
|
||||||
}
|
}
|
||||||
visitor::walk_f_string_element(self, f_string_element);
|
visitor::walk_interpolated_string_element(self, interpolated_string_element);
|
||||||
self.semantic.flags = snapshot;
|
self.semantic.flags = snapshot;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2717,12 +2744,12 @@ impl<'a> Checker<'a> {
|
|||||||
self.semantic.restore(snapshot);
|
self.semantic.restore(snapshot);
|
||||||
|
|
||||||
if self.enabled(Rule::ForwardAnnotationSyntaxError) {
|
if self.enabled(Rule::ForwardAnnotationSyntaxError) {
|
||||||
self.report_type_diagnostic(Diagnostic::new(
|
self.report_type_diagnostic(
|
||||||
pyflakes::rules::ForwardAnnotationSyntaxError {
|
pyflakes::rules::ForwardAnnotationSyntaxError {
|
||||||
parse_error: parse_error.error.to_string(),
|
parse_error: parse_error.error.to_string(),
|
||||||
},
|
},
|
||||||
string_expr.range(),
|
string_expr.range(),
|
||||||
));
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2863,30 +2890,26 @@ impl<'a> Checker<'a> {
|
|||||||
} else {
|
} else {
|
||||||
if self.semantic.global_scope().uses_star_imports() {
|
if self.semantic.global_scope().uses_star_imports() {
|
||||||
if self.enabled(Rule::UndefinedLocalWithImportStarUsage) {
|
if self.enabled(Rule::UndefinedLocalWithImportStarUsage) {
|
||||||
self.diagnostics.get_mut().push(
|
self.report_diagnostic(
|
||||||
Diagnostic::new(
|
pyflakes::rules::UndefinedLocalWithImportStarUsage {
|
||||||
pyflakes::rules::UndefinedLocalWithImportStarUsage {
|
name: name.to_string(),
|
||||||
name: name.to_string(),
|
},
|
||||||
},
|
range,
|
||||||
range,
|
)
|
||||||
)
|
.set_parent(definition.start());
|
||||||
.with_parent(definition.start()),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if self.enabled(Rule::UndefinedExport) {
|
if self.enabled(Rule::UndefinedExport) {
|
||||||
if is_undefined_export_in_dunder_init_enabled(self.settings)
|
if is_undefined_export_in_dunder_init_enabled(self.settings)
|
||||||
|| !self.path.ends_with("__init__.py")
|
|| !self.path.ends_with("__init__.py")
|
||||||
{
|
{
|
||||||
self.diagnostics.get_mut().push(
|
self.report_diagnostic(
|
||||||
Diagnostic::new(
|
pyflakes::rules::UndefinedExport {
|
||||||
pyflakes::rules::UndefinedExport {
|
name: name.to_string(),
|
||||||
name: name.to_string(),
|
},
|
||||||
},
|
range,
|
||||||
range,
|
)
|
||||||
)
|
.set_parent(definition.start());
|
||||||
.with_parent(definition.start()),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2947,7 +2970,8 @@ pub(crate) fn check_ast(
|
|||||||
cell_offsets: Option<&CellOffsets>,
|
cell_offsets: Option<&CellOffsets>,
|
||||||
notebook_index: Option<&NotebookIndex>,
|
notebook_index: Option<&NotebookIndex>,
|
||||||
target_version: TargetVersion,
|
target_version: TargetVersion,
|
||||||
) -> (Vec<Diagnostic>, Vec<SemanticSyntaxError>) {
|
context: &LintContext,
|
||||||
|
) -> Vec<SemanticSyntaxError> {
|
||||||
let module_path = package
|
let module_path = package
|
||||||
.map(PackageRoot::path)
|
.map(PackageRoot::path)
|
||||||
.and_then(|package| to_module_path(package, path));
|
.and_then(|package| to_module_path(package, path));
|
||||||
@@ -2987,6 +3011,7 @@ pub(crate) fn check_ast(
|
|||||||
cell_offsets,
|
cell_offsets,
|
||||||
notebook_index,
|
notebook_index,
|
||||||
target_version,
|
target_version,
|
||||||
|
context,
|
||||||
);
|
);
|
||||||
checker.bind_builtins();
|
checker.bind_builtins();
|
||||||
|
|
||||||
@@ -3013,10 +3038,137 @@ pub(crate) fn check_ast(
|
|||||||
analyze::deferred_scopes(&checker);
|
analyze::deferred_scopes(&checker);
|
||||||
|
|
||||||
let Checker {
|
let Checker {
|
||||||
diagnostics,
|
semantic_errors, ..
|
||||||
semantic_errors,
|
|
||||||
..
|
|
||||||
} = checker;
|
} = checker;
|
||||||
|
|
||||||
(diagnostics.into_inner(), semantic_errors.into_inner())
|
semantic_errors.into_inner()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A type for collecting diagnostics in a given file.
|
||||||
|
///
|
||||||
|
/// [`LintContext::report_diagnostic`] can be used to obtain a [`DiagnosticGuard`], which will push
|
||||||
|
/// a [`Violation`] to the contained [`OldDiagnostic`] collection on `Drop`.
|
||||||
|
pub(crate) struct LintContext<'a> {
|
||||||
|
diagnostics: RefCell<Vec<OldDiagnostic>>,
|
||||||
|
source_file: &'a SourceFile,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> LintContext<'a> {
|
||||||
|
/// Create a new collector with the given `source_file` and an empty collection of
|
||||||
|
/// `OldDiagnostic`s.
|
||||||
|
pub(crate) fn new(source_file: &'a SourceFile) -> Self {
|
||||||
|
Self {
|
||||||
|
diagnostics: RefCell::default(),
|
||||||
|
source_file,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return a [`DiagnosticGuard`] for reporting a diagnostic.
|
||||||
|
///
|
||||||
|
/// The guard derefs to an [`OldDiagnostic`], so it can be used to further modify the diagnostic
|
||||||
|
/// before it is added to the collection in the collector on `Drop`.
|
||||||
|
pub(crate) fn report_diagnostic<'chk, T: Violation>(
|
||||||
|
&'chk self,
|
||||||
|
kind: T,
|
||||||
|
range: TextRange,
|
||||||
|
) -> DiagnosticGuard<'chk, 'a> {
|
||||||
|
DiagnosticGuard {
|
||||||
|
context: self,
|
||||||
|
diagnostic: Some(OldDiagnostic::new(kind, range, self.source_file)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return a [`DiagnosticGuard`] for reporting a diagnostic if the corresponding rule is
|
||||||
|
/// enabled.
|
||||||
|
///
|
||||||
|
/// Prefer [`DiagnosticsCollector::report_diagnostic`] in general because the conversion from an
|
||||||
|
/// `OldDiagnostic` to a `Rule` is somewhat expensive.
|
||||||
|
pub(crate) fn report_diagnostic_if_enabled<'chk, T: Violation>(
|
||||||
|
&'chk self,
|
||||||
|
kind: T,
|
||||||
|
range: TextRange,
|
||||||
|
settings: &LinterSettings,
|
||||||
|
) -> Option<DiagnosticGuard<'chk, 'a>> {
|
||||||
|
let diagnostic = OldDiagnostic::new(kind, range, self.source_file);
|
||||||
|
if settings.rules.enabled(diagnostic.rule()) {
|
||||||
|
Some(DiagnosticGuard {
|
||||||
|
context: self,
|
||||||
|
diagnostic: Some(diagnostic),
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn into_diagnostics(self) -> Vec<OldDiagnostic> {
|
||||||
|
self.diagnostics.into_inner()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn is_empty(&self) -> bool {
|
||||||
|
self.diagnostics.borrow().is_empty()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn as_mut_vec(&mut self) -> &mut Vec<OldDiagnostic> {
|
||||||
|
self.diagnostics.get_mut()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn iter(&mut self) -> impl Iterator<Item = &OldDiagnostic> {
|
||||||
|
self.diagnostics.get_mut().iter()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An abstraction for mutating a diagnostic.
|
||||||
|
///
|
||||||
|
/// Callers can build this guard by starting with `Checker::report_diagnostic`.
|
||||||
|
///
|
||||||
|
/// The primary function of this guard is to add the underlying diagnostic to the `Checker`'s list
|
||||||
|
/// of diagnostics on `Drop`, while dereferencing to the underlying diagnostic for mutations like
|
||||||
|
/// adding fixes or parent ranges.
|
||||||
|
pub(crate) struct DiagnosticGuard<'a, 'b> {
|
||||||
|
/// The parent checker that will receive the diagnostic on `Drop`.
|
||||||
|
context: &'a LintContext<'b>,
|
||||||
|
/// The diagnostic that we want to report.
|
||||||
|
///
|
||||||
|
/// This is always `Some` until the `Drop` (or `defuse`) call.
|
||||||
|
diagnostic: Option<OldDiagnostic>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DiagnosticGuard<'_, '_> {
|
||||||
|
/// Consume the underlying `Diagnostic` without emitting it.
|
||||||
|
///
|
||||||
|
/// In general you should avoid constructing diagnostics that may not be emitted, but this
|
||||||
|
/// method can be used where this is unavoidable.
|
||||||
|
pub(crate) fn defuse(mut self) {
|
||||||
|
self.diagnostic = None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::ops::Deref for DiagnosticGuard<'_, '_> {
|
||||||
|
type Target = OldDiagnostic;
|
||||||
|
|
||||||
|
fn deref(&self) -> &OldDiagnostic {
|
||||||
|
// OK because `self.diagnostic` is only `None` within `Drop`.
|
||||||
|
self.diagnostic.as_ref().unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return a mutable borrow of the diagnostic in this guard.
|
||||||
|
impl std::ops::DerefMut for DiagnosticGuard<'_, '_> {
|
||||||
|
fn deref_mut(&mut self) -> &mut OldDiagnostic {
|
||||||
|
// OK because `self.diagnostic` is only `None` within `Drop`.
|
||||||
|
self.diagnostic.as_mut().unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for DiagnosticGuard<'_, '_> {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
if std::thread::panicking() {
|
||||||
|
// Don't submit diagnostics when panicking because they might be incomplete.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(diagnostic) = self.diagnostic.take() {
|
||||||
|
self.context.diagnostics.borrow_mut().push(diagnostic);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
use ruff_diagnostics::Diagnostic;
|
|
||||||
use ruff_python_ast::PythonVersion;
|
use ruff_python_ast::PythonVersion;
|
||||||
use ruff_python_trivia::CommentRanges;
|
use ruff_python_trivia::CommentRanges;
|
||||||
|
|
||||||
use crate::Locator;
|
use crate::Locator;
|
||||||
|
use crate::checkers::ast::LintContext;
|
||||||
use crate::package::PackageRoot;
|
use crate::package::PackageRoot;
|
||||||
use crate::preview::is_allow_nested_roots_enabled;
|
use crate::preview::is_allow_nested_roots_enabled;
|
||||||
use crate::registry::Rule;
|
use crate::registry::Rule;
|
||||||
@@ -20,13 +20,12 @@ pub(crate) fn check_file_path(
|
|||||||
comment_ranges: &CommentRanges,
|
comment_ranges: &CommentRanges,
|
||||||
settings: &LinterSettings,
|
settings: &LinterSettings,
|
||||||
target_version: PythonVersion,
|
target_version: PythonVersion,
|
||||||
) -> Vec<Diagnostic> {
|
context: &LintContext,
|
||||||
let mut diagnostics: Vec<Diagnostic> = vec![];
|
) {
|
||||||
|
|
||||||
// flake8-no-pep420
|
// flake8-no-pep420
|
||||||
if settings.rules.enabled(Rule::ImplicitNamespacePackage) {
|
if settings.rules.enabled(Rule::ImplicitNamespacePackage) {
|
||||||
let allow_nested_roots = is_allow_nested_roots_enabled(settings);
|
let allow_nested_roots = is_allow_nested_roots_enabled(settings);
|
||||||
if let Some(diagnostic) = implicit_namespace_package(
|
implicit_namespace_package(
|
||||||
path,
|
path,
|
||||||
package,
|
package,
|
||||||
locator,
|
locator,
|
||||||
@@ -34,26 +33,17 @@ pub(crate) fn check_file_path(
|
|||||||
&settings.project_root,
|
&settings.project_root,
|
||||||
&settings.src,
|
&settings.src,
|
||||||
allow_nested_roots,
|
allow_nested_roots,
|
||||||
) {
|
context,
|
||||||
diagnostics.push(diagnostic);
|
);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// pep8-naming
|
// pep8-naming
|
||||||
if settings.rules.enabled(Rule::InvalidModuleName) {
|
if settings.rules.enabled(Rule::InvalidModuleName) {
|
||||||
if let Some(diagnostic) =
|
invalid_module_name(path, package, &settings.pep8_naming.ignore_names, context);
|
||||||
invalid_module_name(path, package, &settings.pep8_naming.ignore_names)
|
|
||||||
{
|
|
||||||
diagnostics.push(diagnostic);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// flake8-builtins
|
// flake8-builtins
|
||||||
if settings.rules.enabled(Rule::StdlibModuleShadowing) {
|
if settings.rules.enabled(Rule::StdlibModuleShadowing) {
|
||||||
if let Some(diagnostic) = stdlib_module_shadowing(path, settings, target_version) {
|
stdlib_module_shadowing(path, settings, target_version, context);
|
||||||
diagnostics.push(diagnostic);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
diagnostics
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
//! Lint rules based on import analysis.
|
//! Lint rules based on import analysis.
|
||||||
|
|
||||||
use ruff_diagnostics::Diagnostic;
|
|
||||||
use ruff_notebook::CellOffsets;
|
use ruff_notebook::CellOffsets;
|
||||||
use ruff_python_ast::statement_visitor::StatementVisitor;
|
use ruff_python_ast::statement_visitor::StatementVisitor;
|
||||||
use ruff_python_ast::{ModModule, PySourceType, PythonVersion};
|
use ruff_python_ast::{ModModule, PySourceType, PythonVersion};
|
||||||
@@ -16,6 +15,8 @@ use crate::rules::isort;
|
|||||||
use crate::rules::isort::block::{Block, BlockBuilder};
|
use crate::rules::isort::block::{Block, BlockBuilder};
|
||||||
use crate::settings::LinterSettings;
|
use crate::settings::LinterSettings;
|
||||||
|
|
||||||
|
use super::ast::LintContext;
|
||||||
|
|
||||||
#[expect(clippy::too_many_arguments)]
|
#[expect(clippy::too_many_arguments)]
|
||||||
pub(crate) fn check_imports(
|
pub(crate) fn check_imports(
|
||||||
parsed: &Parsed<ModModule>,
|
parsed: &Parsed<ModModule>,
|
||||||
@@ -28,7 +29,8 @@ pub(crate) fn check_imports(
|
|||||||
source_type: PySourceType,
|
source_type: PySourceType,
|
||||||
cell_offsets: Option<&CellOffsets>,
|
cell_offsets: Option<&CellOffsets>,
|
||||||
target_version: PythonVersion,
|
target_version: PythonVersion,
|
||||||
) -> Vec<Diagnostic> {
|
context: &LintContext,
|
||||||
|
) {
|
||||||
// Extract all import blocks from the AST.
|
// Extract all import blocks from the AST.
|
||||||
let tracker = {
|
let tracker = {
|
||||||
let mut tracker =
|
let mut tracker =
|
||||||
@@ -40,11 +42,10 @@ pub(crate) fn check_imports(
|
|||||||
let blocks: Vec<&Block> = tracker.iter().collect();
|
let blocks: Vec<&Block> = tracker.iter().collect();
|
||||||
|
|
||||||
// Enforce import rules.
|
// Enforce import rules.
|
||||||
let mut diagnostics = vec![];
|
|
||||||
if settings.rules.enabled(Rule::UnsortedImports) {
|
if settings.rules.enabled(Rule::UnsortedImports) {
|
||||||
for block in &blocks {
|
for block in &blocks {
|
||||||
if !block.imports.is_empty() {
|
if !block.imports.is_empty() {
|
||||||
if let Some(diagnostic) = isort::rules::organize_imports(
|
isort::rules::organize_imports(
|
||||||
block,
|
block,
|
||||||
locator,
|
locator,
|
||||||
stylist,
|
stylist,
|
||||||
@@ -54,21 +55,19 @@ pub(crate) fn check_imports(
|
|||||||
source_type,
|
source_type,
|
||||||
parsed.tokens(),
|
parsed.tokens(),
|
||||||
target_version,
|
target_version,
|
||||||
) {
|
context,
|
||||||
diagnostics.push(diagnostic);
|
);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if settings.rules.enabled(Rule::MissingRequiredImport) {
|
if settings.rules.enabled(Rule::MissingRequiredImport) {
|
||||||
diagnostics.extend(isort::rules::add_required_imports(
|
isort::rules::add_required_imports(
|
||||||
parsed,
|
parsed,
|
||||||
locator,
|
locator,
|
||||||
stylist,
|
stylist,
|
||||||
settings,
|
settings,
|
||||||
source_type,
|
source_type,
|
||||||
));
|
context,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
diagnostics
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,11 @@
|
|||||||
use ruff_diagnostics::Diagnostic;
|
|
||||||
use ruff_python_codegen::Stylist;
|
use ruff_python_codegen::Stylist;
|
||||||
use ruff_python_index::Indexer;
|
use ruff_python_index::Indexer;
|
||||||
use ruff_python_parser::{TokenKind, Tokens};
|
use ruff_python_parser::{TokenKind, Tokens};
|
||||||
use ruff_source_file::LineRanges;
|
use ruff_source_file::LineRanges;
|
||||||
use ruff_text_size::{Ranged, TextRange};
|
use ruff_text_size::{Ranged, TextRange};
|
||||||
|
|
||||||
use crate::Locator;
|
|
||||||
use crate::line_width::IndentWidth;
|
use crate::line_width::IndentWidth;
|
||||||
use crate::registry::{AsRule, Rule};
|
use crate::registry::Rule;
|
||||||
use crate::rules::pycodestyle::rules::logical_lines::{
|
use crate::rules::pycodestyle::rules::logical_lines::{
|
||||||
LogicalLines, TokenFlags, extraneous_whitespace, indentation, missing_whitespace,
|
LogicalLines, TokenFlags, extraneous_whitespace, indentation, missing_whitespace,
|
||||||
missing_whitespace_after_keyword, missing_whitespace_around_operator, redundant_backslash,
|
missing_whitespace_after_keyword, missing_whitespace_around_operator, redundant_backslash,
|
||||||
@@ -16,6 +14,9 @@ use crate::rules::pycodestyle::rules::logical_lines::{
|
|||||||
whitespace_before_parameters,
|
whitespace_before_parameters,
|
||||||
};
|
};
|
||||||
use crate::settings::LinterSettings;
|
use crate::settings::LinterSettings;
|
||||||
|
use crate::{Locator, Violation};
|
||||||
|
|
||||||
|
use super::ast::{DiagnosticGuard, LintContext};
|
||||||
|
|
||||||
/// Return the amount of indentation, expanding tabs to the next multiple of the settings' tab size.
|
/// Return the amount of indentation, expanding tabs to the next multiple of the settings' tab size.
|
||||||
pub(crate) fn expand_indent(line: &str, indent_width: IndentWidth) -> usize {
|
pub(crate) fn expand_indent(line: &str, indent_width: IndentWidth) -> usize {
|
||||||
@@ -40,8 +41,9 @@ pub(crate) fn check_logical_lines(
|
|||||||
indexer: &Indexer,
|
indexer: &Indexer,
|
||||||
stylist: &Stylist,
|
stylist: &Stylist,
|
||||||
settings: &LinterSettings,
|
settings: &LinterSettings,
|
||||||
) -> Vec<Diagnostic> {
|
lint_context: &LintContext,
|
||||||
let mut context = LogicalLinesContext::new(settings);
|
) {
|
||||||
|
let mut context = LogicalLinesContext::new(settings, lint_context);
|
||||||
|
|
||||||
let mut prev_line = None;
|
let mut prev_line = None;
|
||||||
let mut prev_indent_level = None;
|
let mut prev_indent_level = None;
|
||||||
@@ -170,7 +172,7 @@ pub(crate) fn check_logical_lines(
|
|||||||
let indent_size = 4;
|
let indent_size = 4;
|
||||||
|
|
||||||
if enforce_indentation {
|
if enforce_indentation {
|
||||||
for diagnostic in indentation(
|
indentation(
|
||||||
&line,
|
&line,
|
||||||
prev_line.as_ref(),
|
prev_line.as_ref(),
|
||||||
indent_char,
|
indent_char,
|
||||||
@@ -178,11 +180,9 @@ pub(crate) fn check_logical_lines(
|
|||||||
prev_indent_level,
|
prev_indent_level,
|
||||||
indent_size,
|
indent_size,
|
||||||
range,
|
range,
|
||||||
) {
|
lint_context,
|
||||||
if settings.rules.enabled(diagnostic.rule()) {
|
settings,
|
||||||
context.push_diagnostic(diagnostic);
|
);
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if !line.is_comment_only() {
|
if !line.is_comment_only() {
|
||||||
@@ -190,26 +190,24 @@ pub(crate) fn check_logical_lines(
|
|||||||
prev_indent_level = Some(indent_level);
|
prev_indent_level = Some(indent_level);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
context.diagnostics
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
pub(crate) struct LogicalLinesContext<'a, 'b> {
|
||||||
pub(crate) struct LogicalLinesContext<'a> {
|
|
||||||
settings: &'a LinterSettings,
|
settings: &'a LinterSettings,
|
||||||
diagnostics: Vec<Diagnostic>,
|
context: &'a LintContext<'b>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> LogicalLinesContext<'a> {
|
impl<'a, 'b> LogicalLinesContext<'a, 'b> {
|
||||||
fn new(settings: &'a LinterSettings) -> Self {
|
fn new(settings: &'a LinterSettings, context: &'a LintContext<'b>) -> Self {
|
||||||
Self {
|
Self { settings, context }
|
||||||
settings,
|
|
||||||
diagnostics: Vec::new(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn push_diagnostic(&mut self, diagnostic: Diagnostic) {
|
pub(crate) fn report_diagnostic<'chk, T: Violation>(
|
||||||
if self.settings.rules.enabled(diagnostic.rule()) {
|
&'chk self,
|
||||||
self.diagnostics.push(diagnostic);
|
kind: T,
|
||||||
}
|
range: TextRange,
|
||||||
|
) -> Option<DiagnosticGuard<'chk, 'a>> {
|
||||||
|
self.context
|
||||||
|
.report_diagnostic_if_enabled(kind, range, self.settings)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,11 +5,9 @@ use std::path::Path;
|
|||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use rustc_hash::FxHashSet;
|
use rustc_hash::FxHashSet;
|
||||||
|
|
||||||
use ruff_diagnostics::{Diagnostic, Edit, Fix};
|
|
||||||
use ruff_python_trivia::CommentRanges;
|
use ruff_python_trivia::CommentRanges;
|
||||||
use ruff_text_size::Ranged;
|
use ruff_text_size::Ranged;
|
||||||
|
|
||||||
use crate::Locator;
|
|
||||||
use crate::fix::edits::delete_comment;
|
use crate::fix::edits::delete_comment;
|
||||||
use crate::noqa::{
|
use crate::noqa::{
|
||||||
Code, Directive, FileExemption, FileNoqaDirectives, NoqaDirectives, NoqaMapping,
|
Code, Directive, FileExemption, FileNoqaDirectives, NoqaDirectives, NoqaMapping,
|
||||||
@@ -21,10 +19,13 @@ use crate::rules::pygrep_hooks;
|
|||||||
use crate::rules::ruff;
|
use crate::rules::ruff;
|
||||||
use crate::rules::ruff::rules::{UnusedCodes, UnusedNOQA};
|
use crate::rules::ruff::rules::{UnusedCodes, UnusedNOQA};
|
||||||
use crate::settings::LinterSettings;
|
use crate::settings::LinterSettings;
|
||||||
|
use crate::{Edit, Fix, Locator};
|
||||||
|
|
||||||
|
use super::ast::LintContext;
|
||||||
|
|
||||||
#[expect(clippy::too_many_arguments)]
|
#[expect(clippy::too_many_arguments)]
|
||||||
pub(crate) fn check_noqa(
|
pub(crate) fn check_noqa(
|
||||||
diagnostics: &mut Vec<Diagnostic>,
|
context: &mut LintContext,
|
||||||
path: &Path,
|
path: &Path,
|
||||||
locator: &Locator,
|
locator: &Locator,
|
||||||
comment_ranges: &CommentRanges,
|
comment_ranges: &CommentRanges,
|
||||||
@@ -46,7 +47,7 @@ pub(crate) fn check_noqa(
|
|||||||
let mut ignored_diagnostics = vec![];
|
let mut ignored_diagnostics = vec![];
|
||||||
|
|
||||||
// Remove any ignored diagnostics.
|
// Remove any ignored diagnostics.
|
||||||
'outer: for (index, diagnostic) in diagnostics.iter().enumerate() {
|
'outer: for (index, diagnostic) in context.iter().enumerate() {
|
||||||
let rule = diagnostic.rule();
|
let rule = diagnostic.rule();
|
||||||
|
|
||||||
if matches!(rule, Rule::BlanketNOQA) {
|
if matches!(rule, Rule::BlanketNOQA) {
|
||||||
@@ -135,11 +136,9 @@ pub(crate) fn check_noqa(
|
|||||||
Directive::All(directive) => {
|
Directive::All(directive) => {
|
||||||
if matches.is_empty() {
|
if matches.is_empty() {
|
||||||
let edit = delete_comment(directive.range(), locator);
|
let edit = delete_comment(directive.range(), locator);
|
||||||
let mut diagnostic =
|
let mut diagnostic = context
|
||||||
Diagnostic::new(UnusedNOQA { codes: None }, directive.range());
|
.report_diagnostic(UnusedNOQA { codes: None }, directive.range());
|
||||||
diagnostic.set_fix(Fix::safe_edit(edit));
|
diagnostic.set_fix(Fix::safe_edit(edit));
|
||||||
|
|
||||||
diagnostics.push(diagnostic);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Directive::Codes(directive) => {
|
Directive::Codes(directive) => {
|
||||||
@@ -159,9 +158,7 @@ pub(crate) fn check_noqa(
|
|||||||
|
|
||||||
if seen_codes.insert(original_code) {
|
if seen_codes.insert(original_code) {
|
||||||
let is_code_used = if is_file_level {
|
let is_code_used = if is_file_level {
|
||||||
diagnostics
|
context.iter().any(|diag| diag.rule().noqa_code() == code)
|
||||||
.iter()
|
|
||||||
.any(|diag| diag.rule().noqa_code() == code)
|
|
||||||
} else {
|
} else {
|
||||||
matches.iter().any(|match_| *match_ == code)
|
matches.iter().any(|match_| *match_ == code)
|
||||||
} || settings
|
} || settings
|
||||||
@@ -212,7 +209,7 @@ pub(crate) fn check_noqa(
|
|||||||
directive.range(),
|
directive.range(),
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
let mut diagnostic = Diagnostic::new(
|
let mut diagnostic = context.report_diagnostic(
|
||||||
UnusedNOQA {
|
UnusedNOQA {
|
||||||
codes: Some(UnusedCodes {
|
codes: Some(UnusedCodes {
|
||||||
disabled: disabled_codes
|
disabled: disabled_codes
|
||||||
@@ -236,7 +233,6 @@ pub(crate) fn check_noqa(
|
|||||||
directive.range(),
|
directive.range(),
|
||||||
);
|
);
|
||||||
diagnostic.set_fix(Fix::safe_edit(edit));
|
diagnostic.set_fix(Fix::safe_edit(edit));
|
||||||
diagnostics.push(diagnostic);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -247,8 +243,8 @@ pub(crate) fn check_noqa(
|
|||||||
&& !per_file_ignores.contains(Rule::RedirectedNOQA)
|
&& !per_file_ignores.contains(Rule::RedirectedNOQA)
|
||||||
&& !exemption.includes(Rule::RedirectedNOQA)
|
&& !exemption.includes(Rule::RedirectedNOQA)
|
||||||
{
|
{
|
||||||
ruff::rules::redirected_noqa(diagnostics, &noqa_directives);
|
ruff::rules::redirected_noqa(context, &noqa_directives);
|
||||||
ruff::rules::redirected_file_noqa(diagnostics, &file_noqa_directives);
|
ruff::rules::redirected_file_noqa(context, &file_noqa_directives);
|
||||||
}
|
}
|
||||||
|
|
||||||
if settings.rules.enabled(Rule::BlanketNOQA)
|
if settings.rules.enabled(Rule::BlanketNOQA)
|
||||||
@@ -256,7 +252,7 @@ pub(crate) fn check_noqa(
|
|||||||
&& !exemption.enumerates(Rule::BlanketNOQA)
|
&& !exemption.enumerates(Rule::BlanketNOQA)
|
||||||
{
|
{
|
||||||
pygrep_hooks::rules::blanket_noqa(
|
pygrep_hooks::rules::blanket_noqa(
|
||||||
diagnostics,
|
context,
|
||||||
&noqa_directives,
|
&noqa_directives,
|
||||||
locator,
|
locator,
|
||||||
&file_noqa_directives,
|
&file_noqa_directives,
|
||||||
@@ -267,7 +263,7 @@ pub(crate) fn check_noqa(
|
|||||||
&& !per_file_ignores.contains(Rule::InvalidRuleCode)
|
&& !per_file_ignores.contains(Rule::InvalidRuleCode)
|
||||||
&& !exemption.enumerates(Rule::InvalidRuleCode)
|
&& !exemption.enumerates(Rule::InvalidRuleCode)
|
||||||
{
|
{
|
||||||
ruff::rules::invalid_noqa_code(diagnostics, &noqa_directives, locator, &settings.external);
|
ruff::rules::invalid_noqa_code(context, &noqa_directives, locator, &settings.external);
|
||||||
}
|
}
|
||||||
|
|
||||||
ignored_diagnostics.sort_unstable();
|
ignored_diagnostics.sort_unstable();
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
//! Lint rules based on checking physical lines.
|
//! Lint rules based on checking physical lines.
|
||||||
|
|
||||||
use ruff_diagnostics::Diagnostic;
|
|
||||||
use ruff_python_codegen::Stylist;
|
use ruff_python_codegen::Stylist;
|
||||||
use ruff_python_index::Indexer;
|
use ruff_python_index::Indexer;
|
||||||
use ruff_source_file::UniversalNewlines;
|
use ruff_source_file::UniversalNewlines;
|
||||||
@@ -17,15 +16,16 @@ use crate::rules::pylint;
|
|||||||
use crate::rules::ruff::rules::indented_form_feed;
|
use crate::rules::ruff::rules::indented_form_feed;
|
||||||
use crate::settings::LinterSettings;
|
use crate::settings::LinterSettings;
|
||||||
|
|
||||||
|
use super::ast::LintContext;
|
||||||
|
|
||||||
pub(crate) fn check_physical_lines(
|
pub(crate) fn check_physical_lines(
|
||||||
locator: &Locator,
|
locator: &Locator,
|
||||||
stylist: &Stylist,
|
stylist: &Stylist,
|
||||||
indexer: &Indexer,
|
indexer: &Indexer,
|
||||||
doc_lines: &[TextSize],
|
doc_lines: &[TextSize],
|
||||||
settings: &LinterSettings,
|
settings: &LinterSettings,
|
||||||
) -> Vec<Diagnostic> {
|
context: &LintContext,
|
||||||
let mut diagnostics: Vec<Diagnostic> = vec![];
|
) {
|
||||||
|
|
||||||
let enforce_doc_line_too_long = settings.rules.enabled(Rule::DocLineTooLong);
|
let enforce_doc_line_too_long = settings.rules.enabled(Rule::DocLineTooLong);
|
||||||
let enforce_line_too_long = settings.rules.enabled(Rule::LineTooLong);
|
let enforce_line_too_long = settings.rules.enabled(Rule::LineTooLong);
|
||||||
let enforce_no_newline_at_end_of_file = settings.rules.enabled(Rule::MissingNewlineAtEndOfFile);
|
let enforce_no_newline_at_end_of_file = settings.rules.enabled(Rule::MissingNewlineAtEndOfFile);
|
||||||
@@ -45,54 +45,38 @@ pub(crate) fn check_physical_lines(
|
|||||||
.is_some()
|
.is_some()
|
||||||
{
|
{
|
||||||
if enforce_doc_line_too_long {
|
if enforce_doc_line_too_long {
|
||||||
if let Some(diagnostic) = doc_line_too_long(&line, comment_ranges, settings) {
|
doc_line_too_long(&line, comment_ranges, settings, context);
|
||||||
diagnostics.push(diagnostic);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if enforce_mixed_spaces_and_tabs {
|
if enforce_mixed_spaces_and_tabs {
|
||||||
if let Some(diagnostic) = mixed_spaces_and_tabs(&line) {
|
mixed_spaces_and_tabs(&line, context);
|
||||||
diagnostics.push(diagnostic);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if enforce_line_too_long {
|
if enforce_line_too_long {
|
||||||
if let Some(diagnostic) = line_too_long(&line, comment_ranges, settings) {
|
line_too_long(&line, comment_ranges, settings, context);
|
||||||
diagnostics.push(diagnostic);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if enforce_bidirectional_unicode {
|
if enforce_bidirectional_unicode {
|
||||||
diagnostics.extend(pylint::rules::bidirectional_unicode(&line));
|
pylint::rules::bidirectional_unicode(&line, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
if enforce_trailing_whitespace || enforce_blank_line_contains_whitespace {
|
if enforce_trailing_whitespace || enforce_blank_line_contains_whitespace {
|
||||||
if let Some(diagnostic) = trailing_whitespace(&line, locator, indexer, settings) {
|
trailing_whitespace(&line, locator, indexer, settings, context);
|
||||||
diagnostics.push(diagnostic);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if settings.rules.enabled(Rule::IndentedFormFeed) {
|
if settings.rules.enabled(Rule::IndentedFormFeed) {
|
||||||
if let Some(diagnostic) = indented_form_feed(&line) {
|
indented_form_feed(&line, context);
|
||||||
diagnostics.push(diagnostic);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if enforce_no_newline_at_end_of_file {
|
if enforce_no_newline_at_end_of_file {
|
||||||
if let Some(diagnostic) = no_newline_at_end_of_file(locator, stylist) {
|
no_newline_at_end_of_file(locator, stylist, context);
|
||||||
diagnostics.push(diagnostic);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if enforce_copyright_notice {
|
if enforce_copyright_notice {
|
||||||
if let Some(diagnostic) = missing_copyright_notice(locator, settings) {
|
missing_copyright_notice(locator, settings, context);
|
||||||
diagnostics.push(diagnostic);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
diagnostics
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@@ -100,8 +84,10 @@ mod tests {
|
|||||||
use ruff_python_codegen::Stylist;
|
use ruff_python_codegen::Stylist;
|
||||||
use ruff_python_index::Indexer;
|
use ruff_python_index::Indexer;
|
||||||
use ruff_python_parser::parse_module;
|
use ruff_python_parser::parse_module;
|
||||||
|
use ruff_source_file::SourceFileBuilder;
|
||||||
|
|
||||||
use crate::Locator;
|
use crate::Locator;
|
||||||
|
use crate::checkers::ast::LintContext;
|
||||||
use crate::line_width::LineLength;
|
use crate::line_width::LineLength;
|
||||||
use crate::registry::Rule;
|
use crate::registry::Rule;
|
||||||
use crate::rules::pycodestyle;
|
use crate::rules::pycodestyle;
|
||||||
@@ -118,6 +104,8 @@ mod tests {
|
|||||||
let stylist = Stylist::from_tokens(parsed.tokens(), locator.contents());
|
let stylist = Stylist::from_tokens(parsed.tokens(), locator.contents());
|
||||||
|
|
||||||
let check_with_max_line_length = |line_length: LineLength| {
|
let check_with_max_line_length = |line_length: LineLength| {
|
||||||
|
let source_file = SourceFileBuilder::new("<filename>", line).finish();
|
||||||
|
let diagnostics = LintContext::new(&source_file);
|
||||||
check_physical_lines(
|
check_physical_lines(
|
||||||
&locator,
|
&locator,
|
||||||
&stylist,
|
&stylist,
|
||||||
@@ -130,7 +118,9 @@ mod tests {
|
|||||||
},
|
},
|
||||||
..LinterSettings::for_rule(Rule::LineTooLong)
|
..LinterSettings::for_rule(Rule::LineTooLong)
|
||||||
},
|
},
|
||||||
)
|
&diagnostics,
|
||||||
|
);
|
||||||
|
diagnostics.into_diagnostics()
|
||||||
};
|
};
|
||||||
let line_length = LineLength::try_from(8).unwrap();
|
let line_length = LineLength::try_from(8).unwrap();
|
||||||
assert_eq!(check_with_max_line_length(line_length), vec![]);
|
assert_eq!(check_with_max_line_length(line_length), vec![]);
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
use ruff_diagnostics::Diagnostic;
|
|
||||||
use ruff_notebook::CellOffsets;
|
use ruff_notebook::CellOffsets;
|
||||||
use ruff_python_ast::PySourceType;
|
use ruff_python_ast::PySourceType;
|
||||||
use ruff_python_codegen::Stylist;
|
use ruff_python_codegen::Stylist;
|
||||||
@@ -19,6 +18,8 @@ use crate::rules::{
|
|||||||
};
|
};
|
||||||
use crate::settings::LinterSettings;
|
use crate::settings::LinterSettings;
|
||||||
|
|
||||||
|
use super::ast::LintContext;
|
||||||
|
|
||||||
#[expect(clippy::too_many_arguments)]
|
#[expect(clippy::too_many_arguments)]
|
||||||
pub(crate) fn check_tokens(
|
pub(crate) fn check_tokens(
|
||||||
tokens: &Tokens,
|
tokens: &Tokens,
|
||||||
@@ -29,8 +30,8 @@ pub(crate) fn check_tokens(
|
|||||||
settings: &LinterSettings,
|
settings: &LinterSettings,
|
||||||
source_type: PySourceType,
|
source_type: PySourceType,
|
||||||
cell_offsets: Option<&CellOffsets>,
|
cell_offsets: Option<&CellOffsets>,
|
||||||
) -> Vec<Diagnostic> {
|
context: &mut LintContext,
|
||||||
let mut diagnostics: Vec<Diagnostic> = vec![];
|
) {
|
||||||
let comment_ranges = indexer.comment_ranges();
|
let comment_ranges = indexer.comment_ranges();
|
||||||
|
|
||||||
if settings.rules.any_enabled(&[
|
if settings.rules.any_enabled(&[
|
||||||
@@ -41,16 +42,23 @@ pub(crate) fn check_tokens(
|
|||||||
Rule::BlankLinesAfterFunctionOrClass,
|
Rule::BlankLinesAfterFunctionOrClass,
|
||||||
Rule::BlankLinesBeforeNestedDefinition,
|
Rule::BlankLinesBeforeNestedDefinition,
|
||||||
]) {
|
]) {
|
||||||
BlankLinesChecker::new(locator, stylist, settings, source_type, cell_offsets)
|
BlankLinesChecker::new(
|
||||||
.check_lines(tokens, &mut diagnostics);
|
locator,
|
||||||
|
stylist,
|
||||||
|
settings,
|
||||||
|
source_type,
|
||||||
|
cell_offsets,
|
||||||
|
context,
|
||||||
|
)
|
||||||
|
.check_lines(tokens);
|
||||||
}
|
}
|
||||||
|
|
||||||
if settings.rules.enabled(Rule::BlanketTypeIgnore) {
|
if settings.rules.enabled(Rule::BlanketTypeIgnore) {
|
||||||
pygrep_hooks::rules::blanket_type_ignore(&mut diagnostics, comment_ranges, locator);
|
pygrep_hooks::rules::blanket_type_ignore(context, comment_ranges, locator);
|
||||||
}
|
}
|
||||||
|
|
||||||
if settings.rules.enabled(Rule::EmptyComment) {
|
if settings.rules.enabled(Rule::EmptyComment) {
|
||||||
pylint::rules::empty_comments(&mut diagnostics, comment_ranges, locator);
|
pylint::rules::empty_comments(context, comment_ranges, locator);
|
||||||
}
|
}
|
||||||
|
|
||||||
if settings
|
if settings
|
||||||
@@ -58,25 +66,20 @@ pub(crate) fn check_tokens(
|
|||||||
.enabled(Rule::AmbiguousUnicodeCharacterComment)
|
.enabled(Rule::AmbiguousUnicodeCharacterComment)
|
||||||
{
|
{
|
||||||
for range in comment_ranges {
|
for range in comment_ranges {
|
||||||
ruff::rules::ambiguous_unicode_character_comment(
|
ruff::rules::ambiguous_unicode_character_comment(context, locator, range, settings);
|
||||||
&mut diagnostics,
|
|
||||||
locator,
|
|
||||||
range,
|
|
||||||
settings,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if settings.rules.enabled(Rule::CommentedOutCode) {
|
if settings.rules.enabled(Rule::CommentedOutCode) {
|
||||||
eradicate::rules::commented_out_code(&mut diagnostics, locator, comment_ranges, settings);
|
eradicate::rules::commented_out_code(context, locator, comment_ranges, settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
if settings.rules.enabled(Rule::UTF8EncodingDeclaration) {
|
if settings.rules.enabled(Rule::UTF8EncodingDeclaration) {
|
||||||
pyupgrade::rules::unnecessary_coding_comment(&mut diagnostics, locator, comment_ranges);
|
pyupgrade::rules::unnecessary_coding_comment(context, locator, comment_ranges);
|
||||||
}
|
}
|
||||||
|
|
||||||
if settings.rules.enabled(Rule::TabIndentation) {
|
if settings.rules.enabled(Rule::TabIndentation) {
|
||||||
pycodestyle::rules::tab_indentation(&mut diagnostics, locator, indexer);
|
pycodestyle::rules::tab_indentation(context, locator, indexer);
|
||||||
}
|
}
|
||||||
|
|
||||||
if settings.rules.any_enabled(&[
|
if settings.rules.any_enabled(&[
|
||||||
@@ -87,7 +90,7 @@ pub(crate) fn check_tokens(
|
|||||||
Rule::InvalidCharacterZeroWidthSpace,
|
Rule::InvalidCharacterZeroWidthSpace,
|
||||||
]) {
|
]) {
|
||||||
for token in tokens {
|
for token in tokens {
|
||||||
pylint::rules::invalid_string_characters(&mut diagnostics, token, locator);
|
pylint::rules::invalid_string_characters(context, token, locator);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -97,7 +100,7 @@ pub(crate) fn check_tokens(
|
|||||||
Rule::UselessSemicolon,
|
Rule::UselessSemicolon,
|
||||||
]) {
|
]) {
|
||||||
pycodestyle::rules::compound_statements(
|
pycodestyle::rules::compound_statements(
|
||||||
&mut diagnostics,
|
context,
|
||||||
tokens,
|
tokens,
|
||||||
locator,
|
locator,
|
||||||
indexer,
|
indexer,
|
||||||
@@ -110,13 +113,7 @@ pub(crate) fn check_tokens(
|
|||||||
Rule::SingleLineImplicitStringConcatenation,
|
Rule::SingleLineImplicitStringConcatenation,
|
||||||
Rule::MultiLineImplicitStringConcatenation,
|
Rule::MultiLineImplicitStringConcatenation,
|
||||||
]) {
|
]) {
|
||||||
flake8_implicit_str_concat::rules::implicit(
|
flake8_implicit_str_concat::rules::implicit(context, tokens, locator, indexer, settings);
|
||||||
&mut diagnostics,
|
|
||||||
tokens,
|
|
||||||
locator,
|
|
||||||
indexer,
|
|
||||||
settings,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if settings.rules.any_enabled(&[
|
if settings.rules.any_enabled(&[
|
||||||
@@ -124,15 +121,15 @@ pub(crate) fn check_tokens(
|
|||||||
Rule::TrailingCommaOnBareTuple,
|
Rule::TrailingCommaOnBareTuple,
|
||||||
Rule::ProhibitedTrailingComma,
|
Rule::ProhibitedTrailingComma,
|
||||||
]) {
|
]) {
|
||||||
flake8_commas::rules::trailing_commas(&mut diagnostics, tokens, locator, indexer);
|
flake8_commas::rules::trailing_commas(context, tokens, locator, indexer);
|
||||||
}
|
}
|
||||||
|
|
||||||
if settings.rules.enabled(Rule::ExtraneousParentheses) {
|
if settings.rules.enabled(Rule::ExtraneousParentheses) {
|
||||||
pyupgrade::rules::extraneous_parentheses(&mut diagnostics, tokens, locator);
|
pyupgrade::rules::extraneous_parentheses(context, tokens, locator);
|
||||||
}
|
}
|
||||||
|
|
||||||
if source_type.is_stub() && settings.rules.enabled(Rule::TypeCommentInStub) {
|
if source_type.is_stub() && settings.rules.enabled(Rule::TypeCommentInStub) {
|
||||||
flake8_pyi::rules::type_comment_in_stub(&mut diagnostics, locator, comment_ranges);
|
flake8_pyi::rules::type_comment_in_stub(context, locator, comment_ranges);
|
||||||
}
|
}
|
||||||
|
|
||||||
if settings.rules.any_enabled(&[
|
if settings.rules.any_enabled(&[
|
||||||
@@ -142,13 +139,7 @@ pub(crate) fn check_tokens(
|
|||||||
Rule::ShebangNotFirstLine,
|
Rule::ShebangNotFirstLine,
|
||||||
Rule::ShebangMissingPython,
|
Rule::ShebangMissingPython,
|
||||||
]) {
|
]) {
|
||||||
flake8_executable::rules::from_tokens(
|
flake8_executable::rules::from_tokens(context, path, locator, comment_ranges, settings);
|
||||||
&mut diagnostics,
|
|
||||||
path,
|
|
||||||
locator,
|
|
||||||
comment_ranges,
|
|
||||||
settings,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if settings.rules.any_enabled(&[
|
if settings.rules.any_enabled(&[
|
||||||
@@ -172,19 +163,15 @@ pub(crate) fn check_tokens(
|
|||||||
TodoComment::from_comment(comment, *comment_range, i)
|
TodoComment::from_comment(comment, *comment_range, i)
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
flake8_todos::rules::todos(&mut diagnostics, &todo_comments, locator, comment_ranges);
|
flake8_todos::rules::todos(context, &todo_comments, locator, comment_ranges);
|
||||||
flake8_fixme::rules::todos(&mut diagnostics, &todo_comments);
|
flake8_fixme::rules::todos(context, &todo_comments);
|
||||||
}
|
}
|
||||||
|
|
||||||
if settings.rules.enabled(Rule::TooManyNewlinesAtEndOfFile) {
|
if settings.rules.enabled(Rule::TooManyNewlinesAtEndOfFile) {
|
||||||
pycodestyle::rules::too_many_newlines_at_end_of_file(
|
pycodestyle::rules::too_many_newlines_at_end_of_file(context, tokens, cell_offsets);
|
||||||
&mut diagnostics,
|
|
||||||
tokens,
|
|
||||||
cell_offsets,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
diagnostics.retain(|diagnostic| settings.rules.enabled(diagnostic.rule()));
|
context
|
||||||
|
.as_mut_vec()
|
||||||
diagnostics
|
.retain(|diagnostic| settings.rules.enabled(diagnostic.rule()));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ use std::fmt::Formatter;
|
|||||||
|
|
||||||
use strum_macros::{AsRefStr, EnumIter};
|
use strum_macros::{AsRefStr, EnumIter};
|
||||||
|
|
||||||
use crate::registry::{AsRule, Linter};
|
use crate::registry::Linter;
|
||||||
use crate::rule_selector::is_single_rule_selector;
|
use crate::rule_selector::is_single_rule_selector;
|
||||||
use crate::rules;
|
use crate::rules;
|
||||||
|
|
||||||
@@ -198,6 +198,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> {
|
|||||||
(Pylint, "C0132") => (RuleGroup::Stable, rules::pylint::rules::TypeParamNameMismatch),
|
(Pylint, "C0132") => (RuleGroup::Stable, rules::pylint::rules::TypeParamNameMismatch),
|
||||||
(Pylint, "C0205") => (RuleGroup::Stable, rules::pylint::rules::SingleStringSlots),
|
(Pylint, "C0205") => (RuleGroup::Stable, rules::pylint::rules::SingleStringSlots),
|
||||||
(Pylint, "C0206") => (RuleGroup::Stable, rules::pylint::rules::DictIndexMissingItems),
|
(Pylint, "C0206") => (RuleGroup::Stable, rules::pylint::rules::DictIndexMissingItems),
|
||||||
|
(Pylint, "C0207") => (RuleGroup::Preview, rules::pylint::rules::MissingMaxsplitArg),
|
||||||
(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, "C0415") => (RuleGroup::Preview, rules::pylint::rules::ImportOutsideTopLevel),
|
||||||
@@ -552,6 +553,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> {
|
|||||||
(Pyupgrade, "046") => (RuleGroup::Preview, rules::pyupgrade::rules::NonPEP695GenericClass),
|
(Pyupgrade, "046") => (RuleGroup::Preview, rules::pyupgrade::rules::NonPEP695GenericClass),
|
||||||
(Pyupgrade, "047") => (RuleGroup::Preview, rules::pyupgrade::rules::NonPEP695GenericFunction),
|
(Pyupgrade, "047") => (RuleGroup::Preview, rules::pyupgrade::rules::NonPEP695GenericFunction),
|
||||||
(Pyupgrade, "049") => (RuleGroup::Preview, rules::pyupgrade::rules::PrivateTypeParameter),
|
(Pyupgrade, "049") => (RuleGroup::Preview, rules::pyupgrade::rules::PrivateTypeParameter),
|
||||||
|
(Pyupgrade, "050") => (RuleGroup::Preview, rules::pyupgrade::rules::UselessClassMetaclassType),
|
||||||
|
|
||||||
// pydocstyle
|
// pydocstyle
|
||||||
(Pydocstyle, "100") => (RuleGroup::Stable, rules::pydocstyle::rules::UndocumentedPublicModule),
|
(Pydocstyle, "100") => (RuleGroup::Stable, rules::pydocstyle::rules::UndocumentedPublicModule),
|
||||||
@@ -933,6 +935,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> {
|
|||||||
(Flake8UsePathlib, "207") => (RuleGroup::Stable, rules::flake8_use_pathlib::rules::Glob),
|
(Flake8UsePathlib, "207") => (RuleGroup::Stable, rules::flake8_use_pathlib::rules::Glob),
|
||||||
(Flake8UsePathlib, "208") => (RuleGroup::Stable, rules::flake8_use_pathlib::violations::OsListdir),
|
(Flake8UsePathlib, "208") => (RuleGroup::Stable, rules::flake8_use_pathlib::violations::OsListdir),
|
||||||
(Flake8UsePathlib, "210") => (RuleGroup::Stable, rules::flake8_use_pathlib::rules::InvalidPathlibWithSuffix),
|
(Flake8UsePathlib, "210") => (RuleGroup::Stable, rules::flake8_use_pathlib::rules::InvalidPathlibWithSuffix),
|
||||||
|
(Flake8UsePathlib, "211") => (RuleGroup::Preview, rules::flake8_use_pathlib::violations::OsSymlink),
|
||||||
|
|
||||||
// flake8-logging-format
|
// flake8-logging-format
|
||||||
(Flake8LoggingFormat, "001") => (RuleGroup::Stable, rules::flake8_logging_format::violations::LoggingStringFormat),
|
(Flake8LoggingFormat, "001") => (RuleGroup::Stable, rules::flake8_logging_format::violations::LoggingStringFormat),
|
||||||
@@ -1022,7 +1025,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> {
|
|||||||
(Ruff, "056") => (RuleGroup::Preview, rules::ruff::rules::FalsyDictGetFallback),
|
(Ruff, "056") => (RuleGroup::Preview, rules::ruff::rules::FalsyDictGetFallback),
|
||||||
(Ruff, "057") => (RuleGroup::Preview, rules::ruff::rules::UnnecessaryRound),
|
(Ruff, "057") => (RuleGroup::Preview, rules::ruff::rules::UnnecessaryRound),
|
||||||
(Ruff, "058") => (RuleGroup::Preview, rules::ruff::rules::StarmapZip),
|
(Ruff, "058") => (RuleGroup::Preview, rules::ruff::rules::StarmapZip),
|
||||||
(Ruff, "059") => (RuleGroup::Preview, rules::ruff::rules::UnusedUnpackedVariable),
|
(Ruff, "059") => (RuleGroup::Stable, rules::ruff::rules::UnusedUnpackedVariable),
|
||||||
(Ruff, "060") => (RuleGroup::Preview, rules::ruff::rules::InEmptyCollection),
|
(Ruff, "060") => (RuleGroup::Preview, rules::ruff::rules::InEmptyCollection),
|
||||||
(Ruff, "100") => (RuleGroup::Stable, rules::ruff::rules::UnusedNOQA),
|
(Ruff, "100") => (RuleGroup::Stable, rules::ruff::rules::UnusedNOQA),
|
||||||
(Ruff, "101") => (RuleGroup::Stable, rules::ruff::rules::RedirectedNOQA),
|
(Ruff, "101") => (RuleGroup::Stable, rules::ruff::rules::RedirectedNOQA),
|
||||||
@@ -1154,3 +1157,9 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> {
|
|||||||
_ => return None,
|
_ => return None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Display for Rule {
|
||||||
|
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
|
||||||
|
f.write_str(self.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,14 +1,15 @@
|
|||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use log::debug;
|
use log::debug;
|
||||||
|
|
||||||
|
use ruff_source_file::SourceFile;
|
||||||
use ruff_text_size::{Ranged, TextRange, TextSize};
|
use ruff_text_size::{Ranged, TextRange, TextSize};
|
||||||
|
|
||||||
use crate::{Fix, Violation};
|
use crate::registry::AsRule;
|
||||||
|
use crate::violation::Violation;
|
||||||
|
use crate::{Fix, codes::Rule};
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||||
pub struct Diagnostic {
|
pub struct OldDiagnostic {
|
||||||
/// The identifier of the diagnostic, used to align the diagnostic with a rule.
|
|
||||||
pub name: &'static str,
|
|
||||||
/// The message body to display to the user, to explain the diagnostic.
|
/// The message body to display to the user, to explain the diagnostic.
|
||||||
pub body: String,
|
pub body: String,
|
||||||
/// The message to display to the user, to explain the suggested fix.
|
/// The message to display to the user, to explain the suggested fix.
|
||||||
@@ -16,17 +17,27 @@ pub struct Diagnostic {
|
|||||||
pub range: TextRange,
|
pub range: TextRange,
|
||||||
pub fix: Option<Fix>,
|
pub fix: Option<Fix>,
|
||||||
pub parent: Option<TextSize>,
|
pub parent: Option<TextSize>,
|
||||||
|
|
||||||
|
pub(crate) rule: Rule,
|
||||||
|
|
||||||
|
pub(crate) file: SourceFile,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Diagnostic {
|
impl OldDiagnostic {
|
||||||
pub fn new<T: Violation>(kind: T, range: TextRange) -> Self {
|
// TODO(brent) We temporarily allow this to avoid updating all of the call sites to add
|
||||||
|
// references. I expect this method to go away or change significantly with the rest of the
|
||||||
|
// diagnostic refactor, but if it still exists in this form at the end of the refactor, we
|
||||||
|
// should just update the call sites.
|
||||||
|
#[expect(clippy::needless_pass_by_value)]
|
||||||
|
pub fn new<T: Violation>(kind: T, range: TextRange, file: &SourceFile) -> Self {
|
||||||
Self {
|
Self {
|
||||||
name: T::rule_name(),
|
|
||||||
body: Violation::message(&kind),
|
body: Violation::message(&kind),
|
||||||
suggestion: Violation::fix_title(&kind),
|
suggestion: Violation::fix_title(&kind),
|
||||||
range,
|
range,
|
||||||
fix: None,
|
fix: None,
|
||||||
parent: None,
|
parent: None,
|
||||||
|
rule: T::rule(),
|
||||||
|
file: file.clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,7 +61,7 @@ impl Diagnostic {
|
|||||||
pub fn try_set_fix(&mut self, func: impl FnOnce() -> Result<Fix>) {
|
pub fn try_set_fix(&mut self, func: impl FnOnce() -> Result<Fix>) {
|
||||||
match func() {
|
match func() {
|
||||||
Ok(fix) => self.fix = Some(fix),
|
Ok(fix) => self.fix = Some(fix),
|
||||||
Err(err) => debug!("Failed to create fix for {}: {}", self.name, err),
|
Err(err) => debug!("Failed to create fix for {}: {}", self.rule, err),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,7 +72,7 @@ impl Diagnostic {
|
|||||||
match func() {
|
match func() {
|
||||||
Ok(None) => {}
|
Ok(None) => {}
|
||||||
Ok(Some(fix)) => self.fix = Some(fix),
|
Ok(Some(fix)) => self.fix = Some(fix),
|
||||||
Err(err) => debug!("Failed to create fix for {}: {}", self.name, err),
|
Err(err) => debug!("Failed to create fix for {}: {}", self.rule, err),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -80,7 +91,13 @@ impl Diagnostic {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Ranged for Diagnostic {
|
impl AsRule for OldDiagnostic {
|
||||||
|
fn rule(&self) -> Rule {
|
||||||
|
self.rule
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Ranged for OldDiagnostic {
|
||||||
fn range(&self) -> TextRange {
|
fn range(&self) -> TextRange {
|
||||||
self.range
|
self.range
|
||||||
}
|
}
|
||||||
@@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
|
|
||||||
use ruff_diagnostics::Edit;
|
|
||||||
use ruff_python_ast::parenthesize::parenthesized_range;
|
use ruff_python_ast::parenthesize::parenthesized_range;
|
||||||
use ruff_python_ast::{self as ast, Arguments, ExceptHandler, Expr, ExprList, Parameters, Stmt};
|
use ruff_python_ast::{self as ast, Arguments, ExceptHandler, Expr, ExprList, Parameters, Stmt};
|
||||||
use ruff_python_ast::{AnyNodeRef, ArgOrKeyword};
|
use ruff_python_ast::{AnyNodeRef, ArgOrKeyword};
|
||||||
@@ -16,6 +15,7 @@ use ruff_python_trivia::{
|
|||||||
use ruff_source_file::{LineRanges, NewlineWithTrailingNewline, UniversalNewlines};
|
use ruff_source_file::{LineRanges, NewlineWithTrailingNewline, UniversalNewlines};
|
||||||
use ruff_text_size::{Ranged, TextLen, TextRange, TextSize};
|
use ruff_text_size::{Ranged, TextLen, TextRange, TextSize};
|
||||||
|
|
||||||
|
use crate::Edit;
|
||||||
use crate::Locator;
|
use crate::Locator;
|
||||||
use crate::cst::matchers::{match_function_def, match_indented_block, match_statement};
|
use crate::cst::matchers::{match_function_def, match_indented_block, match_statement};
|
||||||
use crate::fix::codemods;
|
use crate::fix::codemods;
|
||||||
@@ -595,18 +595,17 @@ mod tests {
|
|||||||
use ruff_source_file::SourceFileBuilder;
|
use ruff_source_file::SourceFileBuilder;
|
||||||
use test_case::test_case;
|
use test_case::test_case;
|
||||||
|
|
||||||
use ruff_diagnostics::{Diagnostic, Edit, Fix};
|
|
||||||
use ruff_python_ast::Stmt;
|
use ruff_python_ast::Stmt;
|
||||||
use ruff_python_codegen::Stylist;
|
use ruff_python_codegen::Stylist;
|
||||||
use ruff_python_parser::{parse_expression, parse_module};
|
use ruff_python_parser::{parse_expression, parse_module};
|
||||||
use ruff_text_size::{Ranged, TextRange, TextSize};
|
use ruff_text_size::{Ranged, TextRange, TextSize};
|
||||||
|
|
||||||
use crate::Locator;
|
|
||||||
use crate::fix::apply_fixes;
|
use crate::fix::apply_fixes;
|
||||||
use crate::fix::edits::{
|
use crate::fix::edits::{
|
||||||
add_to_dunder_all, make_redundant_alias, next_stmt_break, trailing_semicolon,
|
add_to_dunder_all, make_redundant_alias, next_stmt_break, trailing_semicolon,
|
||||||
};
|
};
|
||||||
use crate::message::Message;
|
use crate::message::Message;
|
||||||
|
use crate::{Edit, Fix, Locator, OldDiagnostic};
|
||||||
|
|
||||||
/// Parse the given source using [`Mode::Module`] and return the first statement.
|
/// Parse the given source using [`Mode::Module`] and return the first statement.
|
||||||
fn parse_first_stmt(source: &str) -> Result<Stmt> {
|
fn parse_first_stmt(source: &str) -> Result<Stmt> {
|
||||||
@@ -737,24 +736,16 @@ x = 1 \
|
|||||||
let diag = {
|
let diag = {
|
||||||
use crate::rules::pycodestyle::rules::MissingNewlineAtEndOfFile;
|
use crate::rules::pycodestyle::rules::MissingNewlineAtEndOfFile;
|
||||||
let mut iter = edits.into_iter();
|
let mut iter = edits.into_iter();
|
||||||
let diag = Diagnostic::new(
|
let diag = OldDiagnostic::new(
|
||||||
MissingNewlineAtEndOfFile, // The choice of rule here is arbitrary.
|
MissingNewlineAtEndOfFile, // The choice of rule here is arbitrary.
|
||||||
TextRange::default(),
|
TextRange::default(),
|
||||||
|
&SourceFileBuilder::new("<filename>", "<code>").finish(),
|
||||||
)
|
)
|
||||||
.with_fix(Fix::safe_edits(
|
.with_fix(Fix::safe_edits(
|
||||||
iter.next().ok_or(anyhow!("expected edits nonempty"))?,
|
iter.next().ok_or(anyhow!("expected edits nonempty"))?,
|
||||||
iter,
|
iter,
|
||||||
));
|
));
|
||||||
Message::diagnostic(
|
Message::from_diagnostic(diag, None)
|
||||||
diag.name,
|
|
||||||
diag.body,
|
|
||||||
diag.suggestion,
|
|
||||||
diag.range,
|
|
||||||
diag.fix,
|
|
||||||
diag.parent,
|
|
||||||
SourceFileBuilder::new("<filename>", "<code>").finish(),
|
|
||||||
None,
|
|
||||||
)
|
|
||||||
};
|
};
|
||||||
assert_eq!(apply_fixes([diag].iter(), &locator).code, expect);
|
assert_eq!(apply_fixes([diag].iter(), &locator).code, expect);
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ use std::collections::BTreeSet;
|
|||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use rustc_hash::{FxHashMap, FxHashSet};
|
use rustc_hash::{FxHashMap, FxHashSet};
|
||||||
|
|
||||||
use ruff_diagnostics::{Edit, Fix, IsolationLevel, SourceMap};
|
use ruff_diagnostics::{IsolationLevel, SourceMap};
|
||||||
use ruff_text_size::{Ranged, TextLen, TextRange, TextSize};
|
use ruff_text_size::{Ranged, TextLen, TextRange, TextSize};
|
||||||
|
|
||||||
use crate::Locator;
|
use crate::Locator;
|
||||||
@@ -11,6 +11,7 @@ use crate::linter::FixTable;
|
|||||||
use crate::message::Message;
|
use crate::message::Message;
|
||||||
use crate::registry::Rule;
|
use crate::registry::Rule;
|
||||||
use crate::settings::types::UnsafeFixes;
|
use crate::settings::types::UnsafeFixes;
|
||||||
|
use crate::{Edit, Fix};
|
||||||
|
|
||||||
pub(crate) mod codemods;
|
pub(crate) mod codemods;
|
||||||
pub(crate) mod edits;
|
pub(crate) mod edits;
|
||||||
@@ -157,14 +158,16 @@ fn cmp_fix(rule1: Rule, rule2: Rule, fix1: &Fix, fix2: &Fix) -> std::cmp::Orderi
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use ruff_diagnostics::{Diagnostic, Edit, Fix, SourceMarker};
|
use ruff_diagnostics::SourceMarker;
|
||||||
use ruff_source_file::SourceFileBuilder;
|
use ruff_source_file::SourceFileBuilder;
|
||||||
use ruff_text_size::{Ranged, TextSize};
|
use ruff_text_size::{Ranged, TextSize};
|
||||||
|
|
||||||
use crate::Locator;
|
use crate::Locator;
|
||||||
|
use crate::diagnostic::OldDiagnostic;
|
||||||
use crate::fix::{FixResult, apply_fixes};
|
use crate::fix::{FixResult, apply_fixes};
|
||||||
use crate::message::Message;
|
use crate::message::Message;
|
||||||
use crate::rules::pycodestyle::rules::MissingNewlineAtEndOfFile;
|
use crate::rules::pycodestyle::rules::MissingNewlineAtEndOfFile;
|
||||||
|
use crate::{Edit, Fix};
|
||||||
|
|
||||||
fn create_diagnostics(
|
fn create_diagnostics(
|
||||||
filename: &str,
|
filename: &str,
|
||||||
@@ -174,12 +177,12 @@ mod tests {
|
|||||||
edit.into_iter()
|
edit.into_iter()
|
||||||
.map(|edit| {
|
.map(|edit| {
|
||||||
// The choice of rule here is arbitrary.
|
// The choice of rule here is arbitrary.
|
||||||
let diagnostic = Diagnostic::new(MissingNewlineAtEndOfFile, edit.range());
|
let diagnostic = OldDiagnostic::new(
|
||||||
Message::from_diagnostic(
|
MissingNewlineAtEndOfFile,
|
||||||
diagnostic.with_fix(Fix::safe_edit(edit)),
|
edit.range(),
|
||||||
SourceFileBuilder::new(filename, source).finish(),
|
&SourceFileBuilder::new(filename, source).finish(),
|
||||||
None,
|
);
|
||||||
)
|
Message::from_diagnostic(diagnostic.with_fix(Fix::safe_edit(edit)), None)
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
//! Insert statements into Python code.
|
//! Insert statements into Python code.
|
||||||
use std::ops::Add;
|
use std::ops::Add;
|
||||||
|
|
||||||
use ruff_diagnostics::Edit;
|
|
||||||
use ruff_python_ast::Stmt;
|
use ruff_python_ast::Stmt;
|
||||||
use ruff_python_ast::helpers::is_docstring_stmt;
|
use ruff_python_ast::helpers::is_docstring_stmt;
|
||||||
use ruff_python_codegen::Stylist;
|
use ruff_python_codegen::Stylist;
|
||||||
@@ -10,6 +9,7 @@ use ruff_python_trivia::{PythonWhitespace, textwrap::indent};
|
|||||||
use ruff_source_file::{LineRanges, UniversalNewlineIterator};
|
use ruff_source_file::{LineRanges, UniversalNewlineIterator};
|
||||||
use ruff_text_size::{Ranged, TextSize};
|
use ruff_text_size::{Ranged, TextSize};
|
||||||
|
|
||||||
|
use crate::Edit;
|
||||||
use crate::Locator;
|
use crate::Locator;
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ use std::error::Error;
|
|||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use libcst_native::{ImportAlias, Name as cstName, NameOrAttribute};
|
use libcst_native::{ImportAlias, Name as cstName, NameOrAttribute};
|
||||||
|
|
||||||
use ruff_diagnostics::Edit;
|
|
||||||
use ruff_python_ast::{self as ast, Expr, ModModule, Stmt};
|
use ruff_python_ast::{self as ast, Expr, ModModule, Stmt};
|
||||||
use ruff_python_codegen::Stylist;
|
use ruff_python_codegen::Stylist;
|
||||||
use ruff_python_parser::{Parsed, Tokens};
|
use ruff_python_parser::{Parsed, Tokens};
|
||||||
@@ -18,6 +17,7 @@ use ruff_python_semantic::{
|
|||||||
use ruff_python_trivia::textwrap::indent;
|
use ruff_python_trivia::textwrap::indent;
|
||||||
use ruff_text_size::{Ranged, TextSize};
|
use ruff_text_size::{Ranged, TextSize};
|
||||||
|
|
||||||
|
use crate::Edit;
|
||||||
use crate::Locator;
|
use crate::Locator;
|
||||||
use crate::cst::matchers::{match_aliases, match_import_from, match_statement};
|
use crate::cst::matchers::{match_aliases, match_import_from, match_statement};
|
||||||
use crate::fix;
|
use crate::fix;
|
||||||
|
|||||||
@@ -14,12 +14,17 @@ pub use rule_selector::RuleSelector;
|
|||||||
pub use rule_selector::clap_completion::RuleSelectorParser;
|
pub use rule_selector::clap_completion::RuleSelectorParser;
|
||||||
pub use rules::pycodestyle::rules::IOError;
|
pub use rules::pycodestyle::rules::IOError;
|
||||||
|
|
||||||
|
pub use diagnostic::OldDiagnostic;
|
||||||
|
pub(crate) use ruff_diagnostics::{Applicability, Edit, Fix};
|
||||||
|
pub use violation::{AlwaysFixableViolation, FixAvailability, Violation, ViolationMetadata};
|
||||||
|
|
||||||
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
|
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||||
|
|
||||||
mod checkers;
|
mod checkers;
|
||||||
pub mod codes;
|
pub mod codes;
|
||||||
mod comments;
|
mod comments;
|
||||||
mod cst;
|
mod cst;
|
||||||
|
mod diagnostic;
|
||||||
pub mod directives;
|
pub mod directives;
|
||||||
mod doc_lines;
|
mod doc_lines;
|
||||||
mod docstrings;
|
mod docstrings;
|
||||||
@@ -45,6 +50,7 @@ pub mod settings;
|
|||||||
pub mod source_kind;
|
pub mod source_kind;
|
||||||
mod text_helpers;
|
mod text_helpers;
|
||||||
pub mod upstream_categories;
|
pub mod upstream_categories;
|
||||||
|
mod violation;
|
||||||
|
|
||||||
#[cfg(any(test, fuzzing))]
|
#[cfg(any(test, fuzzing))]
|
||||||
pub mod test;
|
pub mod test;
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::cell::LazyCell;
|
|
||||||
use std::ops::Deref;
|
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
use anyhow::{Result, anyhow};
|
use anyhow::{Result, anyhow};
|
||||||
@@ -9,16 +7,16 @@ use itertools::Itertools;
|
|||||||
use ruff_python_parser::semantic_errors::SemanticSyntaxError;
|
use ruff_python_parser::semantic_errors::SemanticSyntaxError;
|
||||||
use rustc_hash::FxHashMap;
|
use rustc_hash::FxHashMap;
|
||||||
|
|
||||||
use ruff_diagnostics::Diagnostic;
|
|
||||||
use ruff_notebook::Notebook;
|
use ruff_notebook::Notebook;
|
||||||
use ruff_python_ast::{ModModule, PySourceType, PythonVersion};
|
use ruff_python_ast::{ModModule, PySourceType, PythonVersion};
|
||||||
use ruff_python_codegen::Stylist;
|
use ruff_python_codegen::Stylist;
|
||||||
use ruff_python_index::Indexer;
|
use ruff_python_index::Indexer;
|
||||||
use ruff_python_parser::{ParseError, ParseOptions, Parsed, UnsupportedSyntaxError};
|
use ruff_python_parser::{ParseError, ParseOptions, Parsed, UnsupportedSyntaxError};
|
||||||
use ruff_source_file::SourceFileBuilder;
|
use ruff_source_file::{SourceFile, SourceFileBuilder};
|
||||||
use ruff_text_size::Ranged;
|
use ruff_text_size::Ranged;
|
||||||
|
|
||||||
use crate::checkers::ast::check_ast;
|
use crate::OldDiagnostic;
|
||||||
|
use crate::checkers::ast::{LintContext, check_ast};
|
||||||
use crate::checkers::filesystem::check_file_path;
|
use crate::checkers::filesystem::check_file_path;
|
||||||
use crate::checkers::imports::check_imports;
|
use crate::checkers::imports::check_imports;
|
||||||
use crate::checkers::noqa::check_noqa;
|
use crate::checkers::noqa::check_noqa;
|
||||||
@@ -113,8 +111,11 @@ pub fn check_path(
|
|||||||
parsed: &Parsed<ModModule>,
|
parsed: &Parsed<ModModule>,
|
||||||
target_version: TargetVersion,
|
target_version: TargetVersion,
|
||||||
) -> Vec<Message> {
|
) -> Vec<Message> {
|
||||||
|
let source_file =
|
||||||
|
SourceFileBuilder::new(path.to_string_lossy().as_ref(), locator.contents()).finish();
|
||||||
|
|
||||||
// Aggregate all diagnostics.
|
// Aggregate all diagnostics.
|
||||||
let mut diagnostics = vec![];
|
let mut diagnostics = LintContext::new(&source_file);
|
||||||
|
|
||||||
// Aggregate all semantic syntax errors.
|
// Aggregate all semantic syntax errors.
|
||||||
let mut semantic_syntax_errors = vec![];
|
let mut semantic_syntax_errors = vec![];
|
||||||
@@ -136,7 +137,7 @@ pub fn check_path(
|
|||||||
.iter_enabled()
|
.iter_enabled()
|
||||||
.any(|rule_code| rule_code.lint_source().is_tokens())
|
.any(|rule_code| rule_code.lint_source().is_tokens())
|
||||||
{
|
{
|
||||||
diagnostics.extend(check_tokens(
|
check_tokens(
|
||||||
tokens,
|
tokens,
|
||||||
path,
|
path,
|
||||||
locator,
|
locator,
|
||||||
@@ -145,7 +146,8 @@ pub fn check_path(
|
|||||||
settings,
|
settings,
|
||||||
source_type,
|
source_type,
|
||||||
source_kind.as_ipy_notebook().map(Notebook::cell_offsets),
|
source_kind.as_ipy_notebook().map(Notebook::cell_offsets),
|
||||||
));
|
&mut diagnostics,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run the filesystem-based rules.
|
// Run the filesystem-based rules.
|
||||||
@@ -154,14 +156,15 @@ pub fn check_path(
|
|||||||
.iter_enabled()
|
.iter_enabled()
|
||||||
.any(|rule_code| rule_code.lint_source().is_filesystem())
|
.any(|rule_code| rule_code.lint_source().is_filesystem())
|
||||||
{
|
{
|
||||||
diagnostics.extend(check_file_path(
|
check_file_path(
|
||||||
path,
|
path,
|
||||||
package,
|
package,
|
||||||
locator,
|
locator,
|
||||||
comment_ranges,
|
comment_ranges,
|
||||||
settings,
|
settings,
|
||||||
target_version.linter_version(),
|
target_version.linter_version(),
|
||||||
));
|
&diagnostics,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run the logical line-based rules.
|
// Run the logical line-based rules.
|
||||||
@@ -170,9 +173,14 @@ pub fn check_path(
|
|||||||
.iter_enabled()
|
.iter_enabled()
|
||||||
.any(|rule_code| rule_code.lint_source().is_logical_lines())
|
.any(|rule_code| rule_code.lint_source().is_logical_lines())
|
||||||
{
|
{
|
||||||
diagnostics.extend(crate::checkers::logical_lines::check_logical_lines(
|
crate::checkers::logical_lines::check_logical_lines(
|
||||||
tokens, locator, indexer, stylist, settings,
|
tokens,
|
||||||
));
|
locator,
|
||||||
|
indexer,
|
||||||
|
stylist,
|
||||||
|
settings,
|
||||||
|
&diagnostics,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run the AST-based rules only if there are no syntax errors.
|
// Run the AST-based rules only if there are no syntax errors.
|
||||||
@@ -180,7 +188,7 @@ pub fn check_path(
|
|||||||
let cell_offsets = source_kind.as_ipy_notebook().map(Notebook::cell_offsets);
|
let cell_offsets = source_kind.as_ipy_notebook().map(Notebook::cell_offsets);
|
||||||
let notebook_index = source_kind.as_ipy_notebook().map(Notebook::index);
|
let notebook_index = source_kind.as_ipy_notebook().map(Notebook::index);
|
||||||
|
|
||||||
let (new_diagnostics, new_semantic_syntax_errors) = check_ast(
|
semantic_syntax_errors.extend(check_ast(
|
||||||
parsed,
|
parsed,
|
||||||
locator,
|
locator,
|
||||||
stylist,
|
stylist,
|
||||||
@@ -194,9 +202,8 @@ pub fn check_path(
|
|||||||
cell_offsets,
|
cell_offsets,
|
||||||
notebook_index,
|
notebook_index,
|
||||||
target_version,
|
target_version,
|
||||||
);
|
&diagnostics,
|
||||||
diagnostics.extend(new_diagnostics);
|
));
|
||||||
semantic_syntax_errors.extend(new_semantic_syntax_errors);
|
|
||||||
|
|
||||||
let use_imports = !directives.isort.skip_file
|
let use_imports = !directives.isort.skip_file
|
||||||
&& settings
|
&& settings
|
||||||
@@ -205,7 +212,7 @@ pub fn check_path(
|
|||||||
.any(|rule_code| rule_code.lint_source().is_imports());
|
.any(|rule_code| rule_code.lint_source().is_imports());
|
||||||
if use_imports || use_doc_lines {
|
if use_imports || use_doc_lines {
|
||||||
if use_imports {
|
if use_imports {
|
||||||
let import_diagnostics = check_imports(
|
check_imports(
|
||||||
parsed,
|
parsed,
|
||||||
locator,
|
locator,
|
||||||
indexer,
|
indexer,
|
||||||
@@ -216,9 +223,8 @@ pub fn check_path(
|
|||||||
source_type,
|
source_type,
|
||||||
cell_offsets,
|
cell_offsets,
|
||||||
target_version.linter_version(),
|
target_version.linter_version(),
|
||||||
|
&diagnostics,
|
||||||
);
|
);
|
||||||
|
|
||||||
diagnostics.extend(import_diagnostics);
|
|
||||||
}
|
}
|
||||||
if use_doc_lines {
|
if use_doc_lines {
|
||||||
doc_lines.extend(doc_lines_from_ast(parsed.suite(), locator));
|
doc_lines.extend(doc_lines_from_ast(parsed.suite(), locator));
|
||||||
@@ -238,9 +244,14 @@ pub fn check_path(
|
|||||||
.iter_enabled()
|
.iter_enabled()
|
||||||
.any(|rule_code| rule_code.lint_source().is_physical_lines())
|
.any(|rule_code| rule_code.lint_source().is_physical_lines())
|
||||||
{
|
{
|
||||||
diagnostics.extend(check_physical_lines(
|
check_physical_lines(
|
||||||
locator, stylist, indexer, &doc_lines, settings,
|
locator,
|
||||||
));
|
stylist,
|
||||||
|
indexer,
|
||||||
|
&doc_lines,
|
||||||
|
settings,
|
||||||
|
&diagnostics,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Raise violations for internal test rules
|
// Raise violations for internal test rules
|
||||||
@@ -250,47 +261,70 @@ pub fn check_path(
|
|||||||
if !settings.rules.enabled(*test_rule) {
|
if !settings.rules.enabled(*test_rule) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let diagnostic = match test_rule {
|
match test_rule {
|
||||||
Rule::StableTestRule => {
|
Rule::StableTestRule => {
|
||||||
test_rules::StableTestRule::diagnostic(locator, comment_ranges)
|
test_rules::StableTestRule::diagnostic(locator, comment_ranges, &diagnostics);
|
||||||
}
|
|
||||||
Rule::StableTestRuleSafeFix => {
|
|
||||||
test_rules::StableTestRuleSafeFix::diagnostic(locator, comment_ranges)
|
|
||||||
}
|
|
||||||
Rule::StableTestRuleUnsafeFix => {
|
|
||||||
test_rules::StableTestRuleUnsafeFix::diagnostic(locator, comment_ranges)
|
|
||||||
}
|
}
|
||||||
|
Rule::StableTestRuleSafeFix => test_rules::StableTestRuleSafeFix::diagnostic(
|
||||||
|
locator,
|
||||||
|
comment_ranges,
|
||||||
|
&diagnostics,
|
||||||
|
),
|
||||||
|
Rule::StableTestRuleUnsafeFix => test_rules::StableTestRuleUnsafeFix::diagnostic(
|
||||||
|
locator,
|
||||||
|
comment_ranges,
|
||||||
|
&diagnostics,
|
||||||
|
),
|
||||||
Rule::StableTestRuleDisplayOnlyFix => {
|
Rule::StableTestRuleDisplayOnlyFix => {
|
||||||
test_rules::StableTestRuleDisplayOnlyFix::diagnostic(locator, comment_ranges)
|
test_rules::StableTestRuleDisplayOnlyFix::diagnostic(
|
||||||
|
locator,
|
||||||
|
comment_ranges,
|
||||||
|
&diagnostics,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
Rule::PreviewTestRule => {
|
Rule::PreviewTestRule => {
|
||||||
test_rules::PreviewTestRule::diagnostic(locator, comment_ranges)
|
test_rules::PreviewTestRule::diagnostic(locator, comment_ranges, &diagnostics);
|
||||||
}
|
}
|
||||||
Rule::DeprecatedTestRule => {
|
Rule::DeprecatedTestRule => {
|
||||||
test_rules::DeprecatedTestRule::diagnostic(locator, comment_ranges)
|
test_rules::DeprecatedTestRule::diagnostic(
|
||||||
|
locator,
|
||||||
|
comment_ranges,
|
||||||
|
&diagnostics,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
Rule::AnotherDeprecatedTestRule => {
|
Rule::AnotherDeprecatedTestRule => {
|
||||||
test_rules::AnotherDeprecatedTestRule::diagnostic(locator, comment_ranges)
|
test_rules::AnotherDeprecatedTestRule::diagnostic(
|
||||||
|
locator,
|
||||||
|
comment_ranges,
|
||||||
|
&diagnostics,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
Rule::RemovedTestRule => {
|
Rule::RemovedTestRule => {
|
||||||
test_rules::RemovedTestRule::diagnostic(locator, comment_ranges)
|
test_rules::RemovedTestRule::diagnostic(locator, comment_ranges, &diagnostics);
|
||||||
}
|
|
||||||
Rule::AnotherRemovedTestRule => {
|
|
||||||
test_rules::AnotherRemovedTestRule::diagnostic(locator, comment_ranges)
|
|
||||||
}
|
|
||||||
Rule::RedirectedToTestRule => {
|
|
||||||
test_rules::RedirectedToTestRule::diagnostic(locator, comment_ranges)
|
|
||||||
}
|
|
||||||
Rule::RedirectedFromTestRule => {
|
|
||||||
test_rules::RedirectedFromTestRule::diagnostic(locator, comment_ranges)
|
|
||||||
}
|
}
|
||||||
|
Rule::AnotherRemovedTestRule => test_rules::AnotherRemovedTestRule::diagnostic(
|
||||||
|
locator,
|
||||||
|
comment_ranges,
|
||||||
|
&diagnostics,
|
||||||
|
),
|
||||||
|
Rule::RedirectedToTestRule => test_rules::RedirectedToTestRule::diagnostic(
|
||||||
|
locator,
|
||||||
|
comment_ranges,
|
||||||
|
&diagnostics,
|
||||||
|
),
|
||||||
|
Rule::RedirectedFromTestRule => test_rules::RedirectedFromTestRule::diagnostic(
|
||||||
|
locator,
|
||||||
|
comment_ranges,
|
||||||
|
&diagnostics,
|
||||||
|
),
|
||||||
Rule::RedirectedFromPrefixTestRule => {
|
Rule::RedirectedFromPrefixTestRule => {
|
||||||
test_rules::RedirectedFromPrefixTestRule::diagnostic(locator, comment_ranges)
|
test_rules::RedirectedFromPrefixTestRule::diagnostic(
|
||||||
|
locator,
|
||||||
|
comment_ranges,
|
||||||
|
&diagnostics,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
_ => unreachable!("All test rules must have an implementation"),
|
_ => unreachable!("All test rules must have an implementation"),
|
||||||
};
|
|
||||||
if let Some(diagnostic) = diagnostic {
|
|
||||||
diagnostics.push(diagnostic);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -308,7 +342,9 @@ pub fn check_path(
|
|||||||
RuleSet::empty()
|
RuleSet::empty()
|
||||||
};
|
};
|
||||||
if !per_file_ignores.is_empty() {
|
if !per_file_ignores.is_empty() {
|
||||||
diagnostics.retain(|diagnostic| !per_file_ignores.contains(diagnostic.rule()));
|
diagnostics
|
||||||
|
.as_mut_vec()
|
||||||
|
.retain(|diagnostic| !per_file_ignores.contains(diagnostic.rule()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enforce `noqa` directives.
|
// Enforce `noqa` directives.
|
||||||
@@ -330,11 +366,13 @@ pub fn check_path(
|
|||||||
);
|
);
|
||||||
if noqa.is_enabled() {
|
if noqa.is_enabled() {
|
||||||
for index in ignored.iter().rev() {
|
for index in ignored.iter().rev() {
|
||||||
diagnostics.swap_remove(*index);
|
diagnostics.as_mut_vec().swap_remove(*index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut diagnostics = diagnostics.into_diagnostics();
|
||||||
|
|
||||||
if parsed.has_valid_syntax() {
|
if parsed.has_valid_syntax() {
|
||||||
// Remove fixes for any rules marked as unfixable.
|
// Remove fixes for any rules marked as unfixable.
|
||||||
for diagnostic in &mut diagnostics {
|
for diagnostic in &mut diagnostics {
|
||||||
@@ -372,9 +410,9 @@ pub fn check_path(
|
|||||||
parsed.errors(),
|
parsed.errors(),
|
||||||
syntax_errors,
|
syntax_errors,
|
||||||
&semantic_syntax_errors,
|
&semantic_syntax_errors,
|
||||||
path,
|
|
||||||
locator,
|
locator,
|
||||||
directives,
|
directives,
|
||||||
|
&source_file,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -438,7 +476,7 @@ pub fn add_noqa_to_path(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generate a [`Message`] for each [`Diagnostic`] triggered by the given source
|
/// Generate a [`Message`] for each [`OldDiagnostic`] triggered by the given source
|
||||||
/// code.
|
/// code.
|
||||||
pub fn lint_only(
|
pub fn lint_only(
|
||||||
path: &Path,
|
path: &Path,
|
||||||
@@ -503,39 +541,28 @@ pub fn lint_only(
|
|||||||
|
|
||||||
/// Convert from diagnostics to messages.
|
/// Convert from diagnostics to messages.
|
||||||
fn diagnostics_to_messages(
|
fn diagnostics_to_messages(
|
||||||
diagnostics: Vec<Diagnostic>,
|
diagnostics: Vec<OldDiagnostic>,
|
||||||
parse_errors: &[ParseError],
|
parse_errors: &[ParseError],
|
||||||
unsupported_syntax_errors: &[UnsupportedSyntaxError],
|
unsupported_syntax_errors: &[UnsupportedSyntaxError],
|
||||||
semantic_syntax_errors: &[SemanticSyntaxError],
|
semantic_syntax_errors: &[SemanticSyntaxError],
|
||||||
path: &Path,
|
|
||||||
locator: &Locator,
|
locator: &Locator,
|
||||||
directives: &Directives,
|
directives: &Directives,
|
||||||
|
source_file: &SourceFile,
|
||||||
) -> Vec<Message> {
|
) -> Vec<Message> {
|
||||||
let file = LazyCell::new(|| {
|
|
||||||
let mut builder =
|
|
||||||
SourceFileBuilder::new(path.to_string_lossy().as_ref(), locator.contents());
|
|
||||||
|
|
||||||
if let Some(line_index) = locator.line_index() {
|
|
||||||
builder.set_line_index(line_index.clone());
|
|
||||||
}
|
|
||||||
|
|
||||||
builder.finish()
|
|
||||||
});
|
|
||||||
|
|
||||||
parse_errors
|
parse_errors
|
||||||
.iter()
|
.iter()
|
||||||
.map(|parse_error| Message::from_parse_error(parse_error, locator, file.deref().clone()))
|
.map(|parse_error| Message::from_parse_error(parse_error, locator, source_file.clone()))
|
||||||
.chain(unsupported_syntax_errors.iter().map(|syntax_error| {
|
.chain(unsupported_syntax_errors.iter().map(|syntax_error| {
|
||||||
Message::from_unsupported_syntax_error(syntax_error, file.deref().clone())
|
Message::from_unsupported_syntax_error(syntax_error, source_file.clone())
|
||||||
}))
|
}))
|
||||||
.chain(
|
.chain(
|
||||||
semantic_syntax_errors
|
semantic_syntax_errors
|
||||||
.iter()
|
.iter()
|
||||||
.map(|error| Message::from_semantic_syntax_error(error, file.deref().clone())),
|
.map(|error| Message::from_semantic_syntax_error(error, source_file.clone())),
|
||||||
)
|
)
|
||||||
.chain(diagnostics.into_iter().map(|diagnostic| {
|
.chain(diagnostics.into_iter().map(|diagnostic| {
|
||||||
let noqa_offset = directives.noqa_line_for.resolve(diagnostic.start());
|
let noqa_offset = directives.noqa_line_for.resolve(diagnostic.start());
|
||||||
Message::from_diagnostic(diagnostic, file.deref().clone(), Some(noqa_offset))
|
Message::from_diagnostic(diagnostic, Some(noqa_offset))
|
||||||
}))
|
}))
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,11 +6,11 @@ use colored::{Color, ColoredString, Colorize, Styles};
|
|||||||
use ruff_text_size::{Ranged, TextRange, TextSize};
|
use ruff_text_size::{Ranged, TextRange, TextSize};
|
||||||
use similar::{ChangeTag, TextDiff};
|
use similar::{ChangeTag, TextDiff};
|
||||||
|
|
||||||
use ruff_diagnostics::{Applicability, Fix};
|
|
||||||
use ruff_source_file::{OneIndexed, SourceFile};
|
use ruff_source_file::{OneIndexed, SourceFile};
|
||||||
|
|
||||||
use crate::message::Message;
|
use crate::message::Message;
|
||||||
use crate::text_helpers::ShowNonprinting;
|
use crate::text_helpers::ShowNonprinting;
|
||||||
|
use crate::{Applicability, Fix};
|
||||||
|
|
||||||
/// Renders a diff that shows the code fixes.
|
/// Renders a diff that shows the code fixes.
|
||||||
///
|
///
|
||||||
|
|||||||
@@ -4,11 +4,11 @@ use serde::ser::SerializeSeq;
|
|||||||
use serde::{Serialize, Serializer};
|
use serde::{Serialize, Serializer};
|
||||||
use serde_json::{Value, json};
|
use serde_json::{Value, json};
|
||||||
|
|
||||||
use ruff_diagnostics::Edit;
|
|
||||||
use ruff_notebook::NotebookIndex;
|
use ruff_notebook::NotebookIndex;
|
||||||
use ruff_source_file::{LineColumn, OneIndexed, SourceCode};
|
use ruff_source_file::{LineColumn, OneIndexed, SourceCode};
|
||||||
use ruff_text_size::Ranged;
|
use ruff_text_size::Ranged;
|
||||||
|
|
||||||
|
use crate::Edit;
|
||||||
use crate::message::{Emitter, EmitterContext, Message};
|
use crate::message::{Emitter, EmitterContext, Message};
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ pub use json_lines::JsonLinesEmitter;
|
|||||||
pub use junit::JunitEmitter;
|
pub use junit::JunitEmitter;
|
||||||
pub use pylint::PylintEmitter;
|
pub use pylint::PylintEmitter;
|
||||||
pub use rdjson::RdjsonEmitter;
|
pub use rdjson::RdjsonEmitter;
|
||||||
use ruff_diagnostics::{Diagnostic, Fix};
|
|
||||||
use ruff_notebook::NotebookIndex;
|
use ruff_notebook::NotebookIndex;
|
||||||
use ruff_python_parser::{ParseError, UnsupportedSyntaxError};
|
use ruff_python_parser::{ParseError, UnsupportedSyntaxError};
|
||||||
use ruff_source_file::{LineColumn, SourceFile};
|
use ruff_source_file::{LineColumn, SourceFile};
|
||||||
@@ -28,6 +27,7 @@ use crate::Locator;
|
|||||||
use crate::codes::NoqaCode;
|
use crate::codes::NoqaCode;
|
||||||
use crate::logging::DisplayParseErrorType;
|
use crate::logging::DisplayParseErrorType;
|
||||||
use crate::registry::Rule;
|
use crate::registry::Rule;
|
||||||
|
use crate::{Fix, OldDiagnostic};
|
||||||
|
|
||||||
mod azure;
|
mod azure;
|
||||||
mod diff;
|
mod diff;
|
||||||
@@ -50,7 +50,7 @@ mod text;
|
|||||||
/// `noqa` offsets.
|
/// `noqa` offsets.
|
||||||
///
|
///
|
||||||
/// For diagnostic messages, the [`db::Diagnostic`]'s primary message contains the
|
/// For diagnostic messages, the [`db::Diagnostic`]'s primary message contains the
|
||||||
/// [`Diagnostic::body`], and the primary annotation optionally contains the suggestion accompanying
|
/// [`OldDiagnostic::body`], and the primary annotation optionally contains the suggestion accompanying
|
||||||
/// a fix. The `db::Diagnostic::id` field contains the kebab-case lint name derived from the `Rule`.
|
/// a fix. The `db::Diagnostic::id` field contains the kebab-case lint name derived from the `Rule`.
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
pub struct Message {
|
pub struct Message {
|
||||||
@@ -60,6 +60,7 @@ pub struct Message {
|
|||||||
pub fix: Option<Fix>,
|
pub fix: Option<Fix>,
|
||||||
pub parent: Option<TextSize>,
|
pub parent: Option<TextSize>,
|
||||||
pub(crate) noqa_offset: Option<TextSize>,
|
pub(crate) noqa_offset: Option<TextSize>,
|
||||||
|
noqa_code: Option<NoqaCode>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Message {
|
impl Message {
|
||||||
@@ -76,12 +77,12 @@ impl Message {
|
|||||||
fix: None,
|
fix: None,
|
||||||
parent: None,
|
parent: None,
|
||||||
noqa_offset: None,
|
noqa_offset: None,
|
||||||
|
noqa_code: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[expect(clippy::too_many_arguments)]
|
#[expect(clippy::too_many_arguments)]
|
||||||
pub fn diagnostic(
|
pub fn diagnostic(
|
||||||
name: &'static str,
|
|
||||||
body: String,
|
body: String,
|
||||||
suggestion: Option<String>,
|
suggestion: Option<String>,
|
||||||
range: TextRange,
|
range: TextRange,
|
||||||
@@ -89,9 +90,10 @@ impl Message {
|
|||||||
parent: Option<TextSize>,
|
parent: Option<TextSize>,
|
||||||
file: SourceFile,
|
file: SourceFile,
|
||||||
noqa_offset: Option<TextSize>,
|
noqa_offset: Option<TextSize>,
|
||||||
|
rule: Rule,
|
||||||
) -> Message {
|
) -> Message {
|
||||||
let mut diagnostic = db::Diagnostic::new(
|
let mut diagnostic = db::Diagnostic::new(
|
||||||
DiagnosticId::Lint(LintName::of(name)),
|
DiagnosticId::Lint(LintName::of(rule.into())),
|
||||||
Severity::Error,
|
Severity::Error,
|
||||||
body,
|
body,
|
||||||
);
|
);
|
||||||
@@ -107,25 +109,22 @@ impl Message {
|
|||||||
fix,
|
fix,
|
||||||
parent,
|
parent,
|
||||||
noqa_offset,
|
noqa_offset,
|
||||||
|
noqa_code: Some(rule.noqa_code()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a [`Message`] from the given [`Diagnostic`] corresponding to a rule violation.
|
/// Create a [`Message`] from the given [`OldDiagnostic`] corresponding to a rule violation.
|
||||||
pub fn from_diagnostic(
|
pub fn from_diagnostic(diagnostic: OldDiagnostic, noqa_offset: Option<TextSize>) -> Message {
|
||||||
diagnostic: Diagnostic,
|
let OldDiagnostic {
|
||||||
file: SourceFile,
|
|
||||||
noqa_offset: Option<TextSize>,
|
|
||||||
) -> Message {
|
|
||||||
let Diagnostic {
|
|
||||||
name,
|
|
||||||
body,
|
body,
|
||||||
suggestion,
|
suggestion,
|
||||||
range,
|
range,
|
||||||
fix,
|
fix,
|
||||||
parent,
|
parent,
|
||||||
|
rule,
|
||||||
|
file,
|
||||||
} = diagnostic;
|
} = diagnostic;
|
||||||
Self::diagnostic(
|
Self::diagnostic(
|
||||||
name,
|
|
||||||
body,
|
body,
|
||||||
suggestion,
|
suggestion,
|
||||||
range,
|
range,
|
||||||
@@ -133,6 +132,7 @@ impl Message {
|
|||||||
parent,
|
parent,
|
||||||
file,
|
file,
|
||||||
noqa_offset,
|
noqa_offset,
|
||||||
|
rule,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -235,7 +235,7 @@ impl Message {
|
|||||||
|
|
||||||
/// Returns the [`NoqaCode`] corresponding to the diagnostic message.
|
/// Returns the [`NoqaCode`] corresponding to the diagnostic message.
|
||||||
pub fn to_noqa_code(&self) -> Option<NoqaCode> {
|
pub fn to_noqa_code(&self) -> Option<NoqaCode> {
|
||||||
self.to_rule().map(|rule| rule.noqa_code())
|
self.noqa_code
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the URL for the rule documentation, if it exists.
|
/// Returns the URL for the rule documentation, if it exists.
|
||||||
@@ -371,7 +371,8 @@ impl<'a> EmitterContext<'a> {
|
|||||||
mod tests {
|
mod tests {
|
||||||
use rustc_hash::FxHashMap;
|
use rustc_hash::FxHashMap;
|
||||||
|
|
||||||
use ruff_diagnostics::{Edit, Fix};
|
use crate::codes::Rule;
|
||||||
|
use crate::{Edit, Fix};
|
||||||
use ruff_notebook::NotebookIndex;
|
use ruff_notebook::NotebookIndex;
|
||||||
use ruff_python_parser::{Mode, ParseOptions, parse_unchecked};
|
use ruff_python_parser::{Mode, ParseOptions, parse_unchecked};
|
||||||
use ruff_source_file::{OneIndexed, SourceFileBuilder};
|
use ruff_source_file::{OneIndexed, SourceFileBuilder};
|
||||||
@@ -417,7 +418,6 @@ def fibonacci(n):
|
|||||||
|
|
||||||
let unused_import_start = TextSize::from(7);
|
let unused_import_start = TextSize::from(7);
|
||||||
let unused_import = Message::diagnostic(
|
let unused_import = Message::diagnostic(
|
||||||
"unused-import",
|
|
||||||
"`os` imported but unused".to_string(),
|
"`os` imported but unused".to_string(),
|
||||||
Some("Remove unused import: `os`".to_string()),
|
Some("Remove unused import: `os`".to_string()),
|
||||||
TextRange::new(unused_import_start, TextSize::from(9)),
|
TextRange::new(unused_import_start, TextSize::from(9)),
|
||||||
@@ -428,11 +428,11 @@ def fibonacci(n):
|
|||||||
None,
|
None,
|
||||||
fib_source.clone(),
|
fib_source.clone(),
|
||||||
Some(unused_import_start),
|
Some(unused_import_start),
|
||||||
|
Rule::UnusedImport,
|
||||||
);
|
);
|
||||||
|
|
||||||
let unused_variable_start = TextSize::from(94);
|
let unused_variable_start = TextSize::from(94);
|
||||||
let unused_variable = Message::diagnostic(
|
let unused_variable = Message::diagnostic(
|
||||||
"unused-variable",
|
|
||||||
"Local variable `x` is assigned to but never used".to_string(),
|
"Local variable `x` is assigned to but never used".to_string(),
|
||||||
Some("Remove assignment to unused variable `x`".to_string()),
|
Some("Remove assignment to unused variable `x`".to_string()),
|
||||||
TextRange::new(unused_variable_start, TextSize::from(95)),
|
TextRange::new(unused_variable_start, TextSize::from(95)),
|
||||||
@@ -443,13 +443,13 @@ def fibonacci(n):
|
|||||||
None,
|
None,
|
||||||
fib_source,
|
fib_source,
|
||||||
Some(unused_variable_start),
|
Some(unused_variable_start),
|
||||||
|
Rule::UnusedVariable,
|
||||||
);
|
);
|
||||||
|
|
||||||
let file_2 = r"if a == 1: pass";
|
let file_2 = r"if a == 1: pass";
|
||||||
|
|
||||||
let undefined_name_start = TextSize::from(3);
|
let undefined_name_start = TextSize::from(3);
|
||||||
let undefined_name = Message::diagnostic(
|
let undefined_name = Message::diagnostic(
|
||||||
"undefined-name",
|
|
||||||
"Undefined name `a`".to_string(),
|
"Undefined name `a`".to_string(),
|
||||||
None,
|
None,
|
||||||
TextRange::new(undefined_name_start, TextSize::from(4)),
|
TextRange::new(undefined_name_start, TextSize::from(4)),
|
||||||
@@ -457,6 +457,7 @@ def fibonacci(n):
|
|||||||
None,
|
None,
|
||||||
SourceFileBuilder::new("undef.py", file_2).finish(),
|
SourceFileBuilder::new("undef.py", file_2).finish(),
|
||||||
Some(undefined_name_start),
|
Some(undefined_name_start),
|
||||||
|
Rule::UndefinedName,
|
||||||
);
|
);
|
||||||
|
|
||||||
vec![unused_import, unused_variable, undefined_name]
|
vec![unused_import, unused_variable, undefined_name]
|
||||||
@@ -479,7 +480,6 @@ def foo():
|
|||||||
|
|
||||||
let unused_import_os_start = TextSize::from(16);
|
let unused_import_os_start = TextSize::from(16);
|
||||||
let unused_import_os = Message::diagnostic(
|
let unused_import_os = Message::diagnostic(
|
||||||
"unused-import",
|
|
||||||
"`os` imported but unused".to_string(),
|
"`os` imported but unused".to_string(),
|
||||||
Some("Remove unused import: `os`".to_string()),
|
Some("Remove unused import: `os`".to_string()),
|
||||||
TextRange::new(unused_import_os_start, TextSize::from(18)),
|
TextRange::new(unused_import_os_start, TextSize::from(18)),
|
||||||
@@ -490,11 +490,11 @@ def foo():
|
|||||||
None,
|
None,
|
||||||
notebook_source.clone(),
|
notebook_source.clone(),
|
||||||
Some(unused_import_os_start),
|
Some(unused_import_os_start),
|
||||||
|
Rule::UnusedImport,
|
||||||
);
|
);
|
||||||
|
|
||||||
let unused_import_math_start = TextSize::from(35);
|
let unused_import_math_start = TextSize::from(35);
|
||||||
let unused_import_math = Message::diagnostic(
|
let unused_import_math = Message::diagnostic(
|
||||||
"unused-import",
|
|
||||||
"`math` imported but unused".to_string(),
|
"`math` imported but unused".to_string(),
|
||||||
Some("Remove unused import: `math`".to_string()),
|
Some("Remove unused import: `math`".to_string()),
|
||||||
TextRange::new(unused_import_math_start, TextSize::from(39)),
|
TextRange::new(unused_import_math_start, TextSize::from(39)),
|
||||||
@@ -505,11 +505,11 @@ def foo():
|
|||||||
None,
|
None,
|
||||||
notebook_source.clone(),
|
notebook_source.clone(),
|
||||||
Some(unused_import_math_start),
|
Some(unused_import_math_start),
|
||||||
|
Rule::UnusedImport,
|
||||||
);
|
);
|
||||||
|
|
||||||
let unused_variable_start = TextSize::from(98);
|
let unused_variable_start = TextSize::from(98);
|
||||||
let unused_variable = Message::diagnostic(
|
let unused_variable = Message::diagnostic(
|
||||||
"unused-variable",
|
|
||||||
"Local variable `x` is assigned to but never used".to_string(),
|
"Local variable `x` is assigned to but never used".to_string(),
|
||||||
Some("Remove assignment to unused variable `x`".to_string()),
|
Some("Remove assignment to unused variable `x`".to_string()),
|
||||||
TextRange::new(unused_variable_start, TextSize::from(99)),
|
TextRange::new(unused_variable_start, TextSize::from(99)),
|
||||||
@@ -520,6 +520,7 @@ def foo():
|
|||||||
None,
|
None,
|
||||||
notebook_source,
|
notebook_source,
|
||||||
Some(unused_variable_start),
|
Some(unused_variable_start),
|
||||||
|
Rule::UnusedVariable,
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut notebook_indexes = FxHashMap::default();
|
let mut notebook_indexes = FxHashMap::default();
|
||||||
|
|||||||
@@ -4,10 +4,10 @@ use serde::ser::SerializeSeq;
|
|||||||
use serde::{Serialize, Serializer};
|
use serde::{Serialize, Serializer};
|
||||||
use serde_json::{Value, json};
|
use serde_json::{Value, json};
|
||||||
|
|
||||||
use ruff_diagnostics::Edit;
|
|
||||||
use ruff_source_file::SourceCode;
|
use ruff_source_file::SourceCode;
|
||||||
use ruff_text_size::Ranged;
|
use ruff_text_size::Ranged;
|
||||||
|
|
||||||
|
use crate::Edit;
|
||||||
use crate::message::{Emitter, EmitterContext, LineColumn, Message};
|
use crate::message::{Emitter, EmitterContext, LineColumn, Message};
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
|
|||||||
@@ -9,11 +9,11 @@ use anyhow::Result;
|
|||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use log::warn;
|
use log::warn;
|
||||||
|
|
||||||
use ruff_diagnostics::Edit;
|
|
||||||
use ruff_python_trivia::{CommentRanges, Cursor, indentation_at_offset};
|
use ruff_python_trivia::{CommentRanges, Cursor, indentation_at_offset};
|
||||||
use ruff_source_file::{LineEnding, LineRanges};
|
use ruff_source_file::{LineEnding, LineRanges};
|
||||||
use ruff_text_size::{Ranged, TextLen, TextRange, TextSize};
|
use ruff_text_size::{Ranged, TextLen, TextRange, TextSize};
|
||||||
|
|
||||||
|
use crate::Edit;
|
||||||
use crate::Locator;
|
use crate::Locator;
|
||||||
use crate::codes::NoqaCode;
|
use crate::codes::NoqaCode;
|
||||||
use crate::fs::relativize_path;
|
use crate::fs::relativize_path;
|
||||||
@@ -1221,7 +1221,6 @@ mod tests {
|
|||||||
|
|
||||||
use insta::assert_debug_snapshot;
|
use insta::assert_debug_snapshot;
|
||||||
|
|
||||||
use ruff_diagnostics::{Diagnostic, Edit};
|
|
||||||
use ruff_python_trivia::CommentRanges;
|
use ruff_python_trivia::CommentRanges;
|
||||||
use ruff_source_file::{LineEnding, SourceFileBuilder};
|
use ruff_source_file::{LineEnding, SourceFileBuilder};
|
||||||
use ruff_text_size::{Ranged, TextLen, TextRange, TextSize};
|
use ruff_text_size::{Ranged, TextLen, TextRange, TextSize};
|
||||||
@@ -1234,6 +1233,7 @@ mod tests {
|
|||||||
use crate::rules::pycodestyle::rules::{AmbiguousVariableName, UselessSemicolon};
|
use crate::rules::pycodestyle::rules::{AmbiguousVariableName, UselessSemicolon};
|
||||||
use crate::rules::pyflakes::rules::UnusedVariable;
|
use crate::rules::pyflakes::rules::UnusedVariable;
|
||||||
use crate::rules::pyupgrade::rules::PrintfStringFormatting;
|
use crate::rules::pyupgrade::rules::PrintfStringFormatting;
|
||||||
|
use crate::{Edit, OldDiagnostic};
|
||||||
use crate::{Locator, generate_noqa_edits};
|
use crate::{Locator, generate_noqa_edits};
|
||||||
|
|
||||||
fn assert_lexed_ranges_match_slices(
|
fn assert_lexed_ranges_match_slices(
|
||||||
@@ -1252,14 +1252,9 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Create a [`Message`] with a placeholder filename and rule code from `diagnostic`.
|
/// Create a [`Message`] with a placeholder filename and rule code from `diagnostic`.
|
||||||
fn message_from_diagnostic(
|
fn message_from_diagnostic(diagnostic: OldDiagnostic) -> Message {
|
||||||
diagnostic: Diagnostic,
|
|
||||||
path: impl AsRef<Path>,
|
|
||||||
source: &str,
|
|
||||||
) -> Message {
|
|
||||||
let noqa_offset = diagnostic.start();
|
let noqa_offset = diagnostic.start();
|
||||||
let file = SourceFileBuilder::new(path.as_ref().to_string_lossy(), source).finish();
|
Message::from_diagnostic(diagnostic, Some(noqa_offset))
|
||||||
Message::from_diagnostic(diagnostic, file, Some(noqa_offset))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -2842,13 +2837,15 @@ mod tests {
|
|||||||
assert_eq!(count, 0);
|
assert_eq!(count, 0);
|
||||||
assert_eq!(output, format!("{contents}"));
|
assert_eq!(output, format!("{contents}"));
|
||||||
|
|
||||||
let messages = [Diagnostic::new(
|
let source_file = SourceFileBuilder::new(path.to_string_lossy(), contents).finish();
|
||||||
|
let messages = [OldDiagnostic::new(
|
||||||
UnusedVariable {
|
UnusedVariable {
|
||||||
name: "x".to_string(),
|
name: "x".to_string(),
|
||||||
},
|
},
|
||||||
TextRange::new(TextSize::from(0), TextSize::from(0)),
|
TextRange::new(TextSize::from(0), TextSize::from(0)),
|
||||||
|
&source_file,
|
||||||
)]
|
)]
|
||||||
.map(|d| message_from_diagnostic(d, path, contents));
|
.map(message_from_diagnostic);
|
||||||
|
|
||||||
let contents = "x = 1";
|
let contents = "x = 1";
|
||||||
let noqa_line_for = NoqaMapping::default();
|
let noqa_line_for = NoqaMapping::default();
|
||||||
@@ -2864,19 +2861,22 @@ mod tests {
|
|||||||
assert_eq!(count, 1);
|
assert_eq!(count, 1);
|
||||||
assert_eq!(output, "x = 1 # noqa: F841\n");
|
assert_eq!(output, "x = 1 # noqa: F841\n");
|
||||||
|
|
||||||
|
let source_file = SourceFileBuilder::new(path.to_string_lossy(), contents).finish();
|
||||||
let messages = [
|
let messages = [
|
||||||
Diagnostic::new(
|
OldDiagnostic::new(
|
||||||
AmbiguousVariableName("x".to_string()),
|
AmbiguousVariableName("x".to_string()),
|
||||||
TextRange::new(TextSize::from(0), TextSize::from(0)),
|
TextRange::new(TextSize::from(0), TextSize::from(0)),
|
||||||
|
&source_file,
|
||||||
),
|
),
|
||||||
Diagnostic::new(
|
OldDiagnostic::new(
|
||||||
UnusedVariable {
|
UnusedVariable {
|
||||||
name: "x".to_string(),
|
name: "x".to_string(),
|
||||||
},
|
},
|
||||||
TextRange::new(TextSize::from(0), TextSize::from(0)),
|
TextRange::new(TextSize::from(0), TextSize::from(0)),
|
||||||
|
&source_file,
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
.map(|d| message_from_diagnostic(d, path, contents));
|
.map(message_from_diagnostic);
|
||||||
let contents = "x = 1 # noqa: E741\n";
|
let contents = "x = 1 # noqa: E741\n";
|
||||||
let noqa_line_for = NoqaMapping::default();
|
let noqa_line_for = NoqaMapping::default();
|
||||||
let comment_ranges =
|
let comment_ranges =
|
||||||
@@ -2893,19 +2893,22 @@ mod tests {
|
|||||||
assert_eq!(count, 1);
|
assert_eq!(count, 1);
|
||||||
assert_eq!(output, "x = 1 # noqa: E741, F841\n");
|
assert_eq!(output, "x = 1 # noqa: E741, F841\n");
|
||||||
|
|
||||||
|
let source_file = SourceFileBuilder::new(path.to_string_lossy(), contents).finish();
|
||||||
let messages = [
|
let messages = [
|
||||||
Diagnostic::new(
|
OldDiagnostic::new(
|
||||||
AmbiguousVariableName("x".to_string()),
|
AmbiguousVariableName("x".to_string()),
|
||||||
TextRange::new(TextSize::from(0), TextSize::from(0)),
|
TextRange::new(TextSize::from(0), TextSize::from(0)),
|
||||||
|
&source_file,
|
||||||
),
|
),
|
||||||
Diagnostic::new(
|
OldDiagnostic::new(
|
||||||
UnusedVariable {
|
UnusedVariable {
|
||||||
name: "x".to_string(),
|
name: "x".to_string(),
|
||||||
},
|
},
|
||||||
TextRange::new(TextSize::from(0), TextSize::from(0)),
|
TextRange::new(TextSize::from(0), TextSize::from(0)),
|
||||||
|
&source_file,
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
.map(|d| message_from_diagnostic(d, path, contents));
|
.map(message_from_diagnostic);
|
||||||
let contents = "x = 1 # noqa";
|
let contents = "x = 1 # noqa";
|
||||||
let noqa_line_for = NoqaMapping::default();
|
let noqa_line_for = NoqaMapping::default();
|
||||||
let comment_ranges =
|
let comment_ranges =
|
||||||
@@ -2936,11 +2939,13 @@ print(
|
|||||||
)
|
)
|
||||||
"#;
|
"#;
|
||||||
let noqa_line_for = [TextRange::new(8.into(), 68.into())].into_iter().collect();
|
let noqa_line_for = [TextRange::new(8.into(), 68.into())].into_iter().collect();
|
||||||
let messages = [Diagnostic::new(
|
let source_file = SourceFileBuilder::new(path.to_string_lossy(), source).finish();
|
||||||
|
let messages = [OldDiagnostic::new(
|
||||||
PrintfStringFormatting,
|
PrintfStringFormatting,
|
||||||
TextRange::new(12.into(), 79.into()),
|
TextRange::new(12.into(), 79.into()),
|
||||||
|
&source_file,
|
||||||
)]
|
)]
|
||||||
.map(|d| message_from_diagnostic(d, path, source));
|
.map(message_from_diagnostic);
|
||||||
let comment_ranges = CommentRanges::default();
|
let comment_ranges = CommentRanges::default();
|
||||||
let edits = generate_noqa_edits(
|
let edits = generate_noqa_edits(
|
||||||
path,
|
path,
|
||||||
@@ -2968,11 +2973,13 @@ print(
|
|||||||
foo;
|
foo;
|
||||||
bar =
|
bar =
|
||||||
";
|
";
|
||||||
let messages = [Diagnostic::new(
|
let source_file = SourceFileBuilder::new(path.to_string_lossy(), source).finish();
|
||||||
|
let messages = [OldDiagnostic::new(
|
||||||
UselessSemicolon,
|
UselessSemicolon,
|
||||||
TextRange::new(4.into(), 5.into()),
|
TextRange::new(4.into(), 5.into()),
|
||||||
|
&source_file,
|
||||||
)]
|
)]
|
||||||
.map(|d| message_from_diagnostic(d, path, source));
|
.map(message_from_diagnostic);
|
||||||
let noqa_line_for = NoqaMapping::default();
|
let noqa_line_for = NoqaMapping::default();
|
||||||
let comment_ranges = CommentRanges::default();
|
let comment_ranges = CommentRanges::default();
|
||||||
let edits = generate_noqa_edits(
|
let edits = generate_noqa_edits(
|
||||||
|
|||||||
@@ -3,16 +3,16 @@ use log::warn;
|
|||||||
use pyproject_toml::PyProjectToml;
|
use pyproject_toml::PyProjectToml;
|
||||||
use ruff_text_size::{TextRange, TextSize};
|
use ruff_text_size::{TextRange, TextSize};
|
||||||
|
|
||||||
use ruff_diagnostics::Diagnostic;
|
|
||||||
use ruff_source_file::SourceFile;
|
use ruff_source_file::SourceFile;
|
||||||
|
|
||||||
use crate::IOError;
|
use crate::IOError;
|
||||||
|
use crate::OldDiagnostic;
|
||||||
use crate::message::Message;
|
use crate::message::Message;
|
||||||
use crate::registry::Rule;
|
use crate::registry::Rule;
|
||||||
use crate::rules::ruff::rules::InvalidPyprojectToml;
|
use crate::rules::ruff::rules::InvalidPyprojectToml;
|
||||||
use crate::settings::LinterSettings;
|
use crate::settings::LinterSettings;
|
||||||
|
|
||||||
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();
|
||||||
};
|
};
|
||||||
@@ -29,8 +29,9 @@ pub fn lint_pyproject_toml(source_file: SourceFile, settings: &LinterSettings) -
|
|||||||
source_file.name(),
|
source_file.name(),
|
||||||
);
|
);
|
||||||
if settings.rules.enabled(Rule::IOError) {
|
if settings.rules.enabled(Rule::IOError) {
|
||||||
let diagnostic = Diagnostic::new(IOError { message }, TextRange::default());
|
let diagnostic =
|
||||||
messages.push(Message::from_diagnostic(diagnostic, source_file, None));
|
OldDiagnostic::new(IOError { message }, TextRange::default(), source_file);
|
||||||
|
messages.push(Message::from_diagnostic(diagnostic, None));
|
||||||
} else {
|
} else {
|
||||||
warn!(
|
warn!(
|
||||||
"{}{}{} {message}",
|
"{}{}{} {message}",
|
||||||
@@ -51,8 +52,12 @@ pub fn lint_pyproject_toml(source_file: SourceFile, settings: &LinterSettings) -
|
|||||||
|
|
||||||
if settings.rules.enabled(Rule::InvalidPyprojectToml) {
|
if settings.rules.enabled(Rule::InvalidPyprojectToml) {
|
||||||
let toml_err = err.message().to_string();
|
let toml_err = err.message().to_string();
|
||||||
let diagnostic = Diagnostic::new(InvalidPyprojectToml { message: toml_err }, range);
|
let diagnostic = OldDiagnostic::new(
|
||||||
messages.push(Message::from_diagnostic(diagnostic, source_file, None));
|
InvalidPyprojectToml { message: toml_err },
|
||||||
|
range,
|
||||||
|
source_file,
|
||||||
|
);
|
||||||
|
messages.push(Message::from_diagnostic(diagnostic, None));
|
||||||
}
|
}
|
||||||
|
|
||||||
messages
|
messages
|
||||||
|
|||||||
@@ -3,13 +3,13 @@
|
|||||||
use anyhow::{Result, anyhow};
|
use anyhow::{Result, anyhow};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
|
|
||||||
use ruff_diagnostics::Edit;
|
|
||||||
use ruff_python_ast as ast;
|
use ruff_python_ast as ast;
|
||||||
use ruff_python_codegen::Stylist;
|
use ruff_python_codegen::Stylist;
|
||||||
use ruff_python_semantic::{Binding, BindingKind, Scope, ScopeId, SemanticModel};
|
use ruff_python_semantic::{Binding, BindingKind, Scope, ScopeId, SemanticModel};
|
||||||
use ruff_python_stdlib::{builtins::is_python_builtin, keyword::is_keyword};
|
use ruff_python_stdlib::{builtins::is_python_builtin, keyword::is_keyword};
|
||||||
use ruff_text_size::Ranged;
|
use ruff_text_size::Ranged;
|
||||||
|
|
||||||
|
use crate::Edit;
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
|
|
||||||
pub(crate) struct Renamer;
|
pub(crate) struct Renamer;
|
||||||
|
|||||||
@@ -1,10 +1,17 @@
|
|||||||
|
use crate::checkers::ast::Checker;
|
||||||
|
use crate::fix::edits::remove_unused_imports;
|
||||||
|
use crate::importer::ImportRequest;
|
||||||
use crate::rules::numpy::helpers::{AttributeSearcher, ImportSearcher};
|
use crate::rules::numpy::helpers::{AttributeSearcher, ImportSearcher};
|
||||||
|
use ruff_diagnostics::{Edit, Fix};
|
||||||
use ruff_python_ast::name::QualifiedNameBuilder;
|
use ruff_python_ast::name::QualifiedNameBuilder;
|
||||||
use ruff_python_ast::statement_visitor::StatementVisitor;
|
use ruff_python_ast::statement_visitor::StatementVisitor;
|
||||||
use ruff_python_ast::visitor::Visitor;
|
use ruff_python_ast::visitor::Visitor;
|
||||||
use ruff_python_ast::{Expr, ExprName, StmtTry};
|
use ruff_python_ast::{Expr, ExprAttribute, ExprName, StmtTry};
|
||||||
use ruff_python_semantic::Exceptions;
|
use ruff_python_semantic::Exceptions;
|
||||||
use ruff_python_semantic::SemanticModel;
|
use ruff_python_semantic::SemanticModel;
|
||||||
|
use ruff_python_semantic::{MemberNameImport, NameImport};
|
||||||
|
use ruff_text_size::Ranged;
|
||||||
|
use ruff_text_size::TextRange;
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
pub(crate) enum Replacement {
|
pub(crate) enum Replacement {
|
||||||
@@ -170,3 +177,70 @@ pub(crate) fn is_airflow_builtin_or_provider(
|
|||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return the [`ast::ExprName`] at the head of the expression, if any.
|
||||||
|
pub(crate) fn match_head(value: &Expr) -> Option<&ExprName> {
|
||||||
|
match value {
|
||||||
|
Expr::Attribute(ExprAttribute { value, .. }) => value.as_name_expr(),
|
||||||
|
Expr::Name(name) => Some(name),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the [`Fix`] that imports the new name and updates where the import is referenced.
|
||||||
|
/// This is used for cases that member name has changed.
|
||||||
|
/// (e.g., `airflow.datasts.Dataset` to `airflow.sdk.Asset`)
|
||||||
|
pub(crate) fn generate_import_edit(
|
||||||
|
expr: &Expr,
|
||||||
|
checker: &Checker,
|
||||||
|
module: &str,
|
||||||
|
name: &str,
|
||||||
|
ranged: TextRange,
|
||||||
|
) -> Option<Fix> {
|
||||||
|
let (import_edit, _) = checker
|
||||||
|
.importer()
|
||||||
|
.get_or_import_symbol(
|
||||||
|
&ImportRequest::import_from(module, name),
|
||||||
|
expr.start(),
|
||||||
|
checker.semantic(),
|
||||||
|
)
|
||||||
|
.ok()?;
|
||||||
|
let replacement_edit = Edit::range_replacement(name.to_string(), ranged.range());
|
||||||
|
Some(Fix::safe_edits(import_edit, [replacement_edit]))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the [`Fix`] that remove the original import and import the same name with new path.
|
||||||
|
/// This is used for cases that member name has not changed.
|
||||||
|
/// (e.g., `airflow.operators.pig_operator.PigOperator` to `airflow.providers.apache.pig.hooks.pig.PigCliHook`)
|
||||||
|
pub(crate) fn generate_remove_and_runtime_import_edit(
|
||||||
|
expr: &Expr,
|
||||||
|
checker: &Checker,
|
||||||
|
module: &str,
|
||||||
|
name: &str,
|
||||||
|
) -> Option<Fix> {
|
||||||
|
let head = match_head(expr)?;
|
||||||
|
let semantic = checker.semantic();
|
||||||
|
let binding = semantic
|
||||||
|
.resolve_name(head)
|
||||||
|
.or_else(|| checker.semantic().lookup_symbol(&head.id))
|
||||||
|
.map(|id| checker.semantic().binding(id))?;
|
||||||
|
let stmt = binding.statement(semantic)?;
|
||||||
|
let remove_edit = remove_unused_imports(
|
||||||
|
std::iter::once(name),
|
||||||
|
stmt,
|
||||||
|
None,
|
||||||
|
checker.locator(),
|
||||||
|
checker.stylist(),
|
||||||
|
checker.indexer(),
|
||||||
|
)
|
||||||
|
.ok()?;
|
||||||
|
let import_edit = checker.importer().add_import(
|
||||||
|
&NameImport::ImportFrom(MemberNameImport::member(
|
||||||
|
(*module).to_string(),
|
||||||
|
name.to_string(),
|
||||||
|
)),
|
||||||
|
expr.start(),
|
||||||
|
);
|
||||||
|
|
||||||
|
Some(Fix::unsafe_edits(remove_edit, [import_edit]))
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
use ruff_diagnostics::{Diagnostic, Violation};
|
|
||||||
use ruff_macros::{ViolationMetadata, derive_message_formats};
|
use ruff_macros::{ViolationMetadata, derive_message_formats};
|
||||||
use ruff_python_ast::Expr;
|
use ruff_python_ast::Expr;
|
||||||
use ruff_python_ast::{self as ast};
|
use ruff_python_ast::{self as ast};
|
||||||
use ruff_python_semantic::Modules;
|
use ruff_python_semantic::Modules;
|
||||||
use ruff_text_size::Ranged;
|
use ruff_text_size::Ranged;
|
||||||
|
|
||||||
|
use crate::Violation;
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
|
|
||||||
/// ## What it does
|
/// ## What it does
|
||||||
@@ -86,6 +86,5 @@ pub(crate) fn dag_no_schedule_argument(checker: &Checker, expr: &Expr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Produce a diagnostic when the `schedule` keyword argument is not found.
|
// Produce a diagnostic when the `schedule` keyword argument is not found.
|
||||||
let diagnostic = Diagnostic::new(AirflowDagNoScheduleArgument, expr.range());
|
checker.report_diagnostic(AirflowDagNoScheduleArgument, expr.range());
|
||||||
checker.report_diagnostic(diagnostic);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,16 @@
|
|||||||
use crate::importer::ImportRequest;
|
use crate::checkers::ast::Checker;
|
||||||
use crate::rules::airflow::helpers::{ProviderReplacement, is_guarded_by_try_except};
|
use crate::rules::airflow::helpers::{
|
||||||
use ruff_diagnostics::{Diagnostic, Edit, Fix, FixAvailability, Violation};
|
ProviderReplacement, generate_import_edit, generate_remove_and_runtime_import_edit,
|
||||||
|
is_guarded_by_try_except,
|
||||||
|
};
|
||||||
use ruff_macros::{ViolationMetadata, derive_message_formats};
|
use ruff_macros::{ViolationMetadata, derive_message_formats};
|
||||||
|
use ruff_python_ast::name::QualifiedName;
|
||||||
use ruff_python_ast::{Expr, ExprAttribute};
|
use ruff_python_ast::{Expr, ExprAttribute};
|
||||||
use ruff_python_semantic::Modules;
|
use ruff_python_semantic::Modules;
|
||||||
use ruff_text_size::Ranged;
|
use ruff_text_size::Ranged;
|
||||||
use ruff_text_size::TextRange;
|
use ruff_text_size::TextRange;
|
||||||
|
|
||||||
use crate::checkers::ast::Checker;
|
use crate::{FixAvailability, Violation};
|
||||||
|
|
||||||
/// ## What it does
|
/// ## What it does
|
||||||
/// Checks for uses of Airflow functions and values that have been moved to it providers.
|
/// Checks for uses of Airflow functions and values that have been moved to it providers.
|
||||||
@@ -28,12 +31,12 @@ use crate::checkers::ast::Checker;
|
|||||||
/// from airflow.providers.fab.auth_manager.fab_auth_manage import FabAuthManager
|
/// from airflow.providers.fab.auth_manager.fab_auth_manage import FabAuthManager
|
||||||
/// ```
|
/// ```
|
||||||
#[derive(ViolationMetadata)]
|
#[derive(ViolationMetadata)]
|
||||||
pub(crate) struct Airflow3MovedToProvider {
|
pub(crate) struct Airflow3MovedToProvider<'a> {
|
||||||
deprecated: String,
|
deprecated: QualifiedName<'a>,
|
||||||
replacement: ProviderReplacement,
|
replacement: ProviderReplacement,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Violation for Airflow3MovedToProvider {
|
impl Violation for Airflow3MovedToProvider<'_> {
|
||||||
const FIX_AVAILABILITY: FixAvailability = FixAvailability::Sometimes;
|
const FIX_AVAILABILITY: FixAvailability = FixAvailability::Sometimes;
|
||||||
|
|
||||||
#[derive_message_formats]
|
#[derive_message_formats]
|
||||||
@@ -65,24 +68,26 @@ impl Violation for Airflow3MovedToProvider {
|
|||||||
|
|
||||||
fn fix_title(&self) -> Option<String> {
|
fn fix_title(&self) -> Option<String> {
|
||||||
let Airflow3MovedToProvider { replacement, .. } = self;
|
let Airflow3MovedToProvider { replacement, .. } = self;
|
||||||
match replacement {
|
if let Some((module, name, provider, version)) = match &replacement {
|
||||||
ProviderReplacement::None => None,
|
|
||||||
ProviderReplacement::AutoImport {
|
ProviderReplacement::AutoImport {
|
||||||
name,
|
|
||||||
module,
|
module,
|
||||||
|
name,
|
||||||
provider,
|
provider,
|
||||||
version,
|
version,
|
||||||
} => Some(format!(
|
} => Some((module, *name, provider, version)),
|
||||||
"Install `apache-airflow-providers-{provider}>={version}` and use `{module}.{name}` instead."
|
|
||||||
)),
|
|
||||||
ProviderReplacement::SourceModuleMovedToProvider {
|
ProviderReplacement::SourceModuleMovedToProvider {
|
||||||
name,
|
|
||||||
module,
|
module,
|
||||||
|
name,
|
||||||
provider,
|
provider,
|
||||||
version,
|
version,
|
||||||
} => Some(format!(
|
} => Some((module, name.as_str(), provider, version)),
|
||||||
"Install `apache-airflow-providers-{provider}>={version}` and use `{module}.{name}` instead."
|
ProviderReplacement::None => None,
|
||||||
)),
|
} {
|
||||||
|
Some(format!(
|
||||||
|
"Install `apache-airflow-providers-{provider}>={version}` and use `{name}` from `{module}` instead."
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1166,7 +1171,7 @@ fn check_names_moved_to_provider(checker: &Checker, expr: &Expr, ranged: TextRan
|
|||||||
[
|
[
|
||||||
"airflow",
|
"airflow",
|
||||||
"sensors",
|
"sensors",
|
||||||
"external_task",
|
"external_task" | "external_task_sensor",
|
||||||
"ExternalTaskSensorLink",
|
"ExternalTaskSensorLink",
|
||||||
] => ProviderReplacement::AutoImport {
|
] => ProviderReplacement::AutoImport {
|
||||||
module: "airflow.providers.standard.sensors.external_task",
|
module: "airflow.providers.standard.sensors.external_task",
|
||||||
@@ -1178,7 +1183,7 @@ fn check_names_moved_to_provider(checker: &Checker, expr: &Expr, ranged: TextRan
|
|||||||
"airflow",
|
"airflow",
|
||||||
"sensors",
|
"sensors",
|
||||||
"external_task_sensor",
|
"external_task_sensor",
|
||||||
rest @ ("ExternalTaskMarker" | "ExternalTaskSensor" | "ExternalTaskSensorLink"),
|
rest @ ("ExternalTaskMarker" | "ExternalTaskSensor"),
|
||||||
] => ProviderReplacement::SourceModuleMovedToProvider {
|
] => ProviderReplacement::SourceModuleMovedToProvider {
|
||||||
module: "airflow.providers.standard.sensors.external_task",
|
module: "airflow.providers.standard.sensors.external_task",
|
||||||
name: (*rest).to_string(),
|
name: (*rest).to_string(),
|
||||||
@@ -1195,34 +1200,38 @@ fn check_names_moved_to_provider(checker: &Checker, expr: &Expr, ranged: TextRan
|
|||||||
_ => return,
|
_ => return,
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut diagnostic = Diagnostic::new(
|
let (module, name) = match &replacement {
|
||||||
Airflow3MovedToProvider {
|
ProviderReplacement::AutoImport { module, name, .. } => (module, *name),
|
||||||
deprecated: qualified_name.to_string(),
|
|
||||||
replacement: replacement.clone(),
|
|
||||||
},
|
|
||||||
ranged.range(),
|
|
||||||
);
|
|
||||||
|
|
||||||
let semantic = checker.semantic();
|
|
||||||
if let Some((module, name)) = match &replacement {
|
|
||||||
ProviderReplacement::AutoImport { module, name, .. } => Some((module, *name)),
|
|
||||||
ProviderReplacement::SourceModuleMovedToProvider { module, name, .. } => {
|
ProviderReplacement::SourceModuleMovedToProvider { module, name, .. } => {
|
||||||
Some((module, name.as_str()))
|
(module, name.as_str())
|
||||||
}
|
}
|
||||||
ProviderReplacement::None => None,
|
ProviderReplacement::None => {
|
||||||
} {
|
checker.report_diagnostic(
|
||||||
if is_guarded_by_try_except(expr, module, name, semantic) {
|
Airflow3MovedToProvider {
|
||||||
|
deprecated: qualified_name,
|
||||||
|
replacement,
|
||||||
|
},
|
||||||
|
ranged,
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
diagnostic.try_set_fix(|| {
|
};
|
||||||
let (import_edit, binding) = checker.importer().get_or_import_symbol(
|
|
||||||
&ImportRequest::import_from(module, name),
|
if is_guarded_by_try_except(expr, module, name, checker.semantic()) {
|
||||||
expr.start(),
|
return;
|
||||||
checker.semantic(),
|
}
|
||||||
)?;
|
|
||||||
let replacement_edit = Edit::range_replacement(binding, ranged.range());
|
let mut diagnostic = checker.report_diagnostic(
|
||||||
Ok(Fix::safe_edits(import_edit, [replacement_edit]))
|
Airflow3MovedToProvider {
|
||||||
});
|
deprecated: qualified_name,
|
||||||
|
replacement: replacement.clone(),
|
||||||
|
},
|
||||||
|
ranged,
|
||||||
|
);
|
||||||
|
|
||||||
|
if let Some(fix) = generate_import_edit(expr, checker, module, name, ranged)
|
||||||
|
.or_else(|| generate_remove_and_runtime_import_edit(expr, checker, module, name))
|
||||||
|
{
|
||||||
|
diagnostic.set_fix(fix);
|
||||||
}
|
}
|
||||||
checker.report_diagnostic(diagnostic);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
use crate::importer::ImportRequest;
|
|
||||||
use crate::rules::airflow::helpers::{
|
use crate::rules::airflow::helpers::{
|
||||||
Replacement, is_airflow_builtin_or_provider, is_guarded_by_try_except,
|
Replacement, generate_import_edit, generate_remove_and_runtime_import_edit,
|
||||||
|
is_airflow_builtin_or_provider, is_guarded_by_try_except,
|
||||||
};
|
};
|
||||||
use ruff_diagnostics::{Diagnostic, Edit, Fix, FixAvailability, Violation};
|
use crate::{Edit, Fix, FixAvailability, Violation};
|
||||||
use ruff_macros::{ViolationMetadata, derive_message_formats};
|
use ruff_macros::{ViolationMetadata, derive_message_formats};
|
||||||
use ruff_python_ast::helpers::map_callable;
|
use ruff_python_ast::helpers::map_callable;
|
||||||
use ruff_python_ast::{
|
use ruff_python_ast::{
|
||||||
@@ -73,10 +73,10 @@ impl Violation for Airflow3Removal {
|
|||||||
Replacement::AttrName(name) => Some(format!("Use `{name}` instead")),
|
Replacement::AttrName(name) => Some(format!("Use `{name}` instead")),
|
||||||
Replacement::Message(message) => Some((*message).to_string()),
|
Replacement::Message(message) => Some((*message).to_string()),
|
||||||
Replacement::AutoImport { module, name } => {
|
Replacement::AutoImport { module, name } => {
|
||||||
Some(format!("Use `{module}.{name}` instead"))
|
Some(format!("Use `{name}` from `{module}` instead."))
|
||||||
}
|
}
|
||||||
Replacement::SourceModuleMoved { module, name } => {
|
Replacement::SourceModuleMoved { module, name } => {
|
||||||
Some(format!("Use `{module}.{name}` instead"))
|
Some(format!("Use `{name}` from `{module}` instead."))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -166,13 +166,13 @@ fn check_function_parameters(checker: &Checker, function_def: &StmtFunctionDef)
|
|||||||
for param in function_def.parameters.iter_non_variadic_params() {
|
for param in function_def.parameters.iter_non_variadic_params() {
|
||||||
let param_name = param.name();
|
let param_name = param.name();
|
||||||
if REMOVED_CONTEXT_KEYS.contains(¶m_name.as_str()) {
|
if REMOVED_CONTEXT_KEYS.contains(¶m_name.as_str()) {
|
||||||
checker.report_diagnostic(Diagnostic::new(
|
checker.report_diagnostic(
|
||||||
Airflow3Removal {
|
Airflow3Removal {
|
||||||
deprecated: param_name.to_string(),
|
deprecated: param_name.to_string(),
|
||||||
replacement: Replacement::None,
|
replacement: Replacement::None,
|
||||||
},
|
},
|
||||||
param_name.range(),
|
param_name.range(),
|
||||||
));
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -200,7 +200,7 @@ fn check_call_arguments(checker: &Checker, qualified_name: &QualifiedName, argum
|
|||||||
segments => {
|
segments => {
|
||||||
if is_airflow_auth_manager(segments) {
|
if is_airflow_auth_manager(segments) {
|
||||||
if !arguments.is_empty() {
|
if !arguments.is_empty() {
|
||||||
checker.report_diagnostic(Diagnostic::new(
|
checker.report_diagnostic(
|
||||||
Airflow3Removal {
|
Airflow3Removal {
|
||||||
deprecated: String::from("appbuilder"),
|
deprecated: String::from("appbuilder"),
|
||||||
replacement: Replacement::Message(
|
replacement: Replacement::Message(
|
||||||
@@ -208,7 +208,7 @@ fn check_call_arguments(checker: &Checker, qualified_name: &QualifiedName, argum
|
|||||||
),
|
),
|
||||||
},
|
},
|
||||||
arguments.range(),
|
arguments.range(),
|
||||||
));
|
);
|
||||||
}
|
}
|
||||||
} else if is_airflow_task_handler(segments) {
|
} else if is_airflow_task_handler(segments) {
|
||||||
diagnostic_for_argument(checker, arguments, "filename_template", None);
|
diagnostic_for_argument(checker, arguments, "filename_template", None);
|
||||||
@@ -305,7 +305,7 @@ fn check_class_attribute(checker: &Checker, attribute_expr: &ExprAttribute) {
|
|||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
let mut diagnostic = Diagnostic::new(
|
let mut diagnostic = checker.report_diagnostic(
|
||||||
Airflow3Removal {
|
Airflow3Removal {
|
||||||
deprecated: attr.to_string(),
|
deprecated: attr.to_string(),
|
||||||
replacement,
|
replacement,
|
||||||
@@ -315,7 +315,6 @@ fn check_class_attribute(checker: &Checker, attribute_expr: &ExprAttribute) {
|
|||||||
if let Some(fix) = fix {
|
if let Some(fix) = fix {
|
||||||
diagnostic.set_fix(fix);
|
diagnostic.set_fix(fix);
|
||||||
}
|
}
|
||||||
checker.report_diagnostic(diagnostic);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Checks whether an Airflow 3.0–removed context key is used in a function decorated with `@task`.
|
/// Checks whether an Airflow 3.0–removed context key is used in a function decorated with `@task`.
|
||||||
@@ -382,13 +381,13 @@ fn check_context_key_usage_in_call(checker: &Checker, call_expr: &ExprCall) {
|
|||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
if value == removed_key {
|
if value == removed_key {
|
||||||
checker.report_diagnostic(Diagnostic::new(
|
checker.report_diagnostic(
|
||||||
Airflow3Removal {
|
Airflow3Removal {
|
||||||
deprecated: removed_key.to_string(),
|
deprecated: removed_key.to_string(),
|
||||||
replacement: Replacement::None,
|
replacement: Replacement::None,
|
||||||
},
|
},
|
||||||
*range,
|
*range,
|
||||||
));
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -423,13 +422,13 @@ fn check_context_key_usage_in_subscript(checker: &Checker, subscript: &ExprSubsc
|
|||||||
}
|
}
|
||||||
|
|
||||||
if REMOVED_CONTEXT_KEYS.contains(&key.to_str()) {
|
if REMOVED_CONTEXT_KEYS.contains(&key.to_str()) {
|
||||||
checker.report_diagnostic(Diagnostic::new(
|
checker.report_diagnostic(
|
||||||
Airflow3Removal {
|
Airflow3Removal {
|
||||||
deprecated: key.to_string(),
|
deprecated: key.to_string(),
|
||||||
replacement: Replacement::None,
|
replacement: Replacement::None,
|
||||||
},
|
},
|
||||||
slice.range(),
|
slice.range(),
|
||||||
));
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -537,7 +536,7 @@ fn check_method(checker: &Checker, call_expr: &ExprCall) {
|
|||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut diagnostic = Diagnostic::new(
|
let mut diagnostic = checker.report_diagnostic(
|
||||||
Airflow3Removal {
|
Airflow3Removal {
|
||||||
deprecated: attr.to_string(),
|
deprecated: attr.to_string(),
|
||||||
replacement,
|
replacement,
|
||||||
@@ -547,7 +546,6 @@ fn check_method(checker: &Checker, call_expr: &ExprCall) {
|
|||||||
if let Some(fix) = fix {
|
if let Some(fix) = fix {
|
||||||
diagnostic.set_fix(fix);
|
diagnostic.set_fix(fix);
|
||||||
}
|
}
|
||||||
checker.report_diagnostic(diagnostic);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check whether a removed Airflow name is used.
|
/// Check whether a removed Airflow name is used.
|
||||||
@@ -616,7 +614,6 @@ fn check_name(checker: &Checker, expr: &Expr, range: TextRange) {
|
|||||||
},
|
},
|
||||||
|
|
||||||
// airflow.configuration
|
// airflow.configuration
|
||||||
// TODO: check whether we could improve it
|
|
||||||
[
|
[
|
||||||
"airflow",
|
"airflow",
|
||||||
"configuration",
|
"configuration",
|
||||||
@@ -966,37 +963,39 @@ fn check_name(checker: &Checker, expr: &Expr, range: TextRange) {
|
|||||||
_ => return,
|
_ => return,
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut diagnostic = Diagnostic::new(
|
let (module, name) = match &replacement {
|
||||||
|
Replacement::AutoImport { module, name } => (module, *name),
|
||||||
|
Replacement::SourceModuleMoved { module, name } => (module, name.as_str()),
|
||||||
|
_ => {
|
||||||
|
checker.report_diagnostic(
|
||||||
|
Airflow3Removal {
|
||||||
|
deprecated: qualified_name.to_string(),
|
||||||
|
replacement: replacement.clone(),
|
||||||
|
},
|
||||||
|
range,
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if is_guarded_by_try_except(expr, module, name, checker.semantic()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let import_target = name.split('.').next().unwrap_or(name);
|
||||||
|
let mut diagnostic = checker.report_diagnostic(
|
||||||
Airflow3Removal {
|
Airflow3Removal {
|
||||||
deprecated: qualified_name.to_string(),
|
deprecated: qualified_name.to_string(),
|
||||||
replacement: replacement.clone(),
|
replacement: replacement.clone(),
|
||||||
},
|
},
|
||||||
range,
|
range,
|
||||||
);
|
);
|
||||||
let semantic = checker.semantic();
|
|
||||||
if let Some((module, name)) = match &replacement {
|
|
||||||
Replacement::AutoImport { module, name } => Some((module, *name)),
|
|
||||||
Replacement::SourceModuleMoved { module, name } => Some((module, name.as_str())),
|
|
||||||
_ => None,
|
|
||||||
} {
|
|
||||||
if is_guarded_by_try_except(expr, module, name, semantic) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let import_target = name.split('.').next().unwrap_or(name);
|
if let Some(fix) = generate_import_edit(expr, checker, module, import_target, range)
|
||||||
|
.or_else(|| generate_remove_and_runtime_import_edit(expr, checker, module, name))
|
||||||
diagnostic.try_set_fix(|| {
|
{
|
||||||
let (import_edit, _) = checker.importer().get_or_import_symbol(
|
diagnostic.set_fix(fix);
|
||||||
&ImportRequest::import_from(module, import_target),
|
|
||||||
expr.start(),
|
|
||||||
checker.semantic(),
|
|
||||||
)?;
|
|
||||||
let replacement_edit = Edit::range_replacement(name.to_string(), range);
|
|
||||||
Ok(Fix::safe_edits(import_edit, [replacement_edit]))
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
checker.report_diagnostic(diagnostic);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check whether a customized Airflow plugin contains removed extensions.
|
/// Check whether a customized Airflow plugin contains removed extensions.
|
||||||
@@ -1028,7 +1027,7 @@ fn check_airflow_plugin_extension(
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
}) {
|
}) {
|
||||||
checker.report_diagnostic(Diagnostic::new(
|
checker.report_diagnostic(
|
||||||
Airflow3Removal {
|
Airflow3Removal {
|
||||||
deprecated: name.to_string(),
|
deprecated: name.to_string(),
|
||||||
replacement: Replacement::Message(
|
replacement: Replacement::Message(
|
||||||
@@ -1036,7 +1035,7 @@ fn check_airflow_plugin_extension(
|
|||||||
),
|
),
|
||||||
},
|
},
|
||||||
expr.range(),
|
expr.range(),
|
||||||
));
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1052,7 +1051,11 @@ fn diagnostic_for_argument(
|
|||||||
let Some(keyword) = arguments.find_keyword(deprecated) else {
|
let Some(keyword) = arguments.find_keyword(deprecated) else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
let mut diagnostic = Diagnostic::new(
|
let range = keyword
|
||||||
|
.arg
|
||||||
|
.as_ref()
|
||||||
|
.map_or_else(|| keyword.range(), Ranged::range);
|
||||||
|
let mut diagnostic = checker.report_diagnostic(
|
||||||
Airflow3Removal {
|
Airflow3Removal {
|
||||||
deprecated: deprecated.to_string(),
|
deprecated: deprecated.to_string(),
|
||||||
replacement: match replacement {
|
replacement: match replacement {
|
||||||
@@ -1060,20 +1063,15 @@ fn diagnostic_for_argument(
|
|||||||
None => Replacement::None,
|
None => Replacement::None,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
keyword
|
range,
|
||||||
.arg
|
|
||||||
.as_ref()
|
|
||||||
.map_or_else(|| keyword.range(), Ranged::range),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
if let Some(replacement) = replacement {
|
if let Some(replacement) = replacement {
|
||||||
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
|
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
|
||||||
replacement.to_string(),
|
replacement.to_string(),
|
||||||
diagnostic.range,
|
range,
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
checker.report_diagnostic(diagnostic);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check whether the symbol is coming from the `secrets` builtin or provider module which ends
|
/// Check whether the symbol is coming from the `secrets` builtin or provider module which ends
|
||||||
|
|||||||
@@ -1,15 +1,16 @@
|
|||||||
use crate::importer::ImportRequest;
|
use crate::checkers::ast::Checker;
|
||||||
|
use crate::rules::airflow::helpers::{
|
||||||
use crate::rules::airflow::helpers::{ProviderReplacement, is_guarded_by_try_except};
|
ProviderReplacement, generate_import_edit, generate_remove_and_runtime_import_edit,
|
||||||
use ruff_diagnostics::{Diagnostic, Edit, Fix, FixAvailability, Violation};
|
is_guarded_by_try_except,
|
||||||
|
};
|
||||||
|
use crate::{FixAvailability, Violation};
|
||||||
use ruff_macros::{ViolationMetadata, derive_message_formats};
|
use ruff_macros::{ViolationMetadata, derive_message_formats};
|
||||||
|
use ruff_python_ast::name::QualifiedName;
|
||||||
use ruff_python_ast::{Expr, ExprAttribute};
|
use ruff_python_ast::{Expr, ExprAttribute};
|
||||||
use ruff_python_semantic::Modules;
|
use ruff_python_semantic::Modules;
|
||||||
use ruff_text_size::Ranged;
|
use ruff_text_size::Ranged;
|
||||||
use ruff_text_size::TextRange;
|
use ruff_text_size::TextRange;
|
||||||
|
|
||||||
use crate::checkers::ast::Checker;
|
|
||||||
|
|
||||||
/// ## What it does
|
/// ## What it does
|
||||||
/// Checks for uses of Airflow functions and values that have been moved to its providers
|
/// Checks for uses of Airflow functions and values that have been moved to its providers
|
||||||
/// but still have a compatibility layer (e.g., `apache-airflow-providers-standard`).
|
/// but still have a compatibility layer (e.g., `apache-airflow-providers-standard`).
|
||||||
@@ -30,12 +31,12 @@ use crate::checkers::ast::Checker;
|
|||||||
/// from airflow.providers.standard.operators.python import PythonOperator
|
/// from airflow.providers.standard.operators.python import PythonOperator
|
||||||
/// ```
|
/// ```
|
||||||
#[derive(ViolationMetadata)]
|
#[derive(ViolationMetadata)]
|
||||||
pub(crate) struct Airflow3SuggestedToMoveToProvider {
|
pub(crate) struct Airflow3SuggestedToMoveToProvider<'a> {
|
||||||
deprecated: String,
|
deprecated: QualifiedName<'a>,
|
||||||
replacement: ProviderReplacement,
|
replacement: ProviderReplacement,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Violation for Airflow3SuggestedToMoveToProvider {
|
impl Violation for Airflow3SuggestedToMoveToProvider<'_> {
|
||||||
const FIX_AVAILABILITY: FixAvailability = FixAvailability::Sometimes;
|
const FIX_AVAILABILITY: FixAvailability = FixAvailability::Sometimes;
|
||||||
#[derive_message_formats]
|
#[derive_message_formats]
|
||||||
fn message(&self) -> String {
|
fn message(&self) -> String {
|
||||||
@@ -77,7 +78,7 @@ impl Violation for Airflow3SuggestedToMoveToProvider {
|
|||||||
provider,
|
provider,
|
||||||
version,
|
version,
|
||||||
} => Some(format!(
|
} => Some(format!(
|
||||||
"Install `apache-airflow-providers-{provider}>={version}` and use `{module}.{name}` instead."
|
"Install `apache-airflow-providers-{provider}>={version}` and use `{name}` from `{module}` instead."
|
||||||
)),
|
)),
|
||||||
ProviderReplacement::SourceModuleMovedToProvider {
|
ProviderReplacement::SourceModuleMovedToProvider {
|
||||||
module,
|
module,
|
||||||
@@ -85,7 +86,7 @@ impl Violation for Airflow3SuggestedToMoveToProvider {
|
|||||||
provider,
|
provider,
|
||||||
version,
|
version,
|
||||||
} => Some(format!(
|
} => Some(format!(
|
||||||
"Install `apache-airflow-providers-{provider}>={version}` and use `{module}.{name}` instead."
|
"Install `apache-airflow-providers-{provider}>={version}` and use `{name}` from `{module}` instead."
|
||||||
)),
|
)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -281,35 +282,37 @@ fn check_names_moved_to_provider(checker: &Checker, expr: &Expr, ranged: TextRan
|
|||||||
_ => return,
|
_ => return,
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut diagnostic = Diagnostic::new(
|
let (module, name) = match &replacement {
|
||||||
Airflow3SuggestedToMoveToProvider {
|
ProviderReplacement::AutoImport { module, name, .. } => (module, *name),
|
||||||
deprecated: qualified_name.to_string(),
|
|
||||||
replacement: replacement.clone(),
|
|
||||||
},
|
|
||||||
ranged.range(),
|
|
||||||
);
|
|
||||||
|
|
||||||
let semantic = checker.semantic();
|
|
||||||
if let Some((module, name)) = match &replacement {
|
|
||||||
ProviderReplacement::AutoImport { module, name, .. } => Some((module, *name)),
|
|
||||||
ProviderReplacement::SourceModuleMovedToProvider { module, name, .. } => {
|
ProviderReplacement::SourceModuleMovedToProvider { module, name, .. } => {
|
||||||
Some((module, name.as_str()))
|
(module, name.as_str())
|
||||||
}
|
}
|
||||||
ProviderReplacement::None => None,
|
ProviderReplacement::None => {
|
||||||
} {
|
checker.report_diagnostic(
|
||||||
if is_guarded_by_try_except(expr, module, name, semantic) {
|
Airflow3SuggestedToMoveToProvider {
|
||||||
|
deprecated: qualified_name,
|
||||||
|
replacement: replacement.clone(),
|
||||||
|
},
|
||||||
|
ranged.range(),
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
diagnostic.try_set_fix(|| {
|
};
|
||||||
let (import_edit, binding) = checker.importer().get_or_import_symbol(
|
|
||||||
&ImportRequest::import_from(module, name),
|
|
||||||
expr.start(),
|
|
||||||
checker.semantic(),
|
|
||||||
)?;
|
|
||||||
let replacement_edit = Edit::range_replacement(binding, ranged.range());
|
|
||||||
Ok(Fix::safe_edits(import_edit, [replacement_edit]))
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
checker.report_diagnostic(diagnostic);
|
if is_guarded_by_try_except(expr, module, name, checker.semantic()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let mut diagnostic = checker.report_diagnostic(
|
||||||
|
Airflow3SuggestedToMoveToProvider {
|
||||||
|
deprecated: qualified_name,
|
||||||
|
replacement: replacement.clone(),
|
||||||
|
},
|
||||||
|
ranged,
|
||||||
|
);
|
||||||
|
|
||||||
|
if let Some(fix) = generate_import_edit(expr, checker, module, name, ranged)
|
||||||
|
.or_else(|| generate_remove_and_runtime_import_edit(expr, checker, module, name))
|
||||||
|
{
|
||||||
|
diagnostic.set_fix(fix);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
use crate::importer::ImportRequest;
|
use crate::rules::airflow::helpers::{Replacement, is_airflow_builtin_or_provider};
|
||||||
use crate::rules::airflow::helpers::{
|
use crate::rules::airflow::helpers::{
|
||||||
Replacement, is_airflow_builtin_or_provider, is_guarded_by_try_except,
|
generate_import_edit, generate_remove_and_runtime_import_edit, is_guarded_by_try_except,
|
||||||
};
|
};
|
||||||
use ruff_diagnostics::{Diagnostic, Edit, Fix, FixAvailability, Violation};
|
use crate::{Edit, Fix, FixAvailability, Violation};
|
||||||
use ruff_macros::{ViolationMetadata, derive_message_formats};
|
use ruff_macros::{ViolationMetadata, derive_message_formats};
|
||||||
use ruff_python_ast::{Arguments, Expr, ExprAttribute, ExprCall, ExprName, name::QualifiedName};
|
use ruff_python_ast::{Arguments, Expr, ExprAttribute, ExprCall, ExprName, name::QualifiedName};
|
||||||
use ruff_python_semantic::Modules;
|
use ruff_python_semantic::Modules;
|
||||||
@@ -72,10 +72,10 @@ impl Violation for Airflow3SuggestedUpdate {
|
|||||||
Replacement::AttrName(name) => Some(format!("Use `{name}` instead")),
|
Replacement::AttrName(name) => Some(format!("Use `{name}` instead")),
|
||||||
Replacement::Message(message) => Some((*message).to_string()),
|
Replacement::Message(message) => Some((*message).to_string()),
|
||||||
Replacement::AutoImport { module, name } => {
|
Replacement::AutoImport { module, name } => {
|
||||||
Some(format!("Use `{module}.{name}` instead"))
|
Some(format!("Use `{name}` from `{module}` instead."))
|
||||||
}
|
}
|
||||||
Replacement::SourceModuleMoved { module, name } => {
|
Replacement::SourceModuleMoved { module, name } => {
|
||||||
Some(format!("Use `{module}.{name}` instead"))
|
Some(format!("Use `{name}` from `{module}` instead."))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -120,7 +120,11 @@ fn diagnostic_for_argument(
|
|||||||
let Some(keyword) = arguments.find_keyword(deprecated) else {
|
let Some(keyword) = arguments.find_keyword(deprecated) else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
let mut diagnostic = Diagnostic::new(
|
let range = keyword
|
||||||
|
.arg
|
||||||
|
.as_ref()
|
||||||
|
.map_or_else(|| keyword.range(), Ranged::range);
|
||||||
|
let mut diagnostic = checker.report_diagnostic(
|
||||||
Airflow3SuggestedUpdate {
|
Airflow3SuggestedUpdate {
|
||||||
deprecated: deprecated.to_string(),
|
deprecated: deprecated.to_string(),
|
||||||
replacement: match replacement {
|
replacement: match replacement {
|
||||||
@@ -128,20 +132,15 @@ fn diagnostic_for_argument(
|
|||||||
None => Replacement::None,
|
None => Replacement::None,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
keyword
|
range,
|
||||||
.arg
|
|
||||||
.as_ref()
|
|
||||||
.map_or_else(|| keyword.range(), Ranged::range),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
if let Some(replacement) = replacement {
|
if let Some(replacement) = replacement {
|
||||||
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
|
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
|
||||||
replacement.to_string(),
|
replacement.to_string(),
|
||||||
diagnostic.range,
|
range,
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
checker.report_diagnostic(diagnostic);
|
|
||||||
}
|
}
|
||||||
/// Check whether a removed Airflow argument is passed.
|
/// Check whether a removed Airflow argument is passed.
|
||||||
///
|
///
|
||||||
@@ -212,7 +211,7 @@ fn check_name(checker: &Checker, expr: &Expr, range: TextRange) {
|
|||||||
name: "AssetAny",
|
name: "AssetAny",
|
||||||
},
|
},
|
||||||
"expand_alias_to_datasets" => Replacement::AutoImport {
|
"expand_alias_to_datasets" => Replacement::AutoImport {
|
||||||
module: "airflow.sdk",
|
module: "airflow.models.asset",
|
||||||
name: "expand_alias_to_assets",
|
name: "expand_alias_to_assets",
|
||||||
},
|
},
|
||||||
_ => return,
|
_ => return,
|
||||||
@@ -257,7 +256,7 @@ fn check_name(checker: &Checker, expr: &Expr, range: TextRange) {
|
|||||||
name: (*rest).to_string(),
|
name: (*rest).to_string(),
|
||||||
},
|
},
|
||||||
["airflow", "models", "baseoperatorlink", "BaseOperatorLink"] => Replacement::AutoImport {
|
["airflow", "models", "baseoperatorlink", "BaseOperatorLink"] => Replacement::AutoImport {
|
||||||
module: "airflow.sdk.definitions.baseoperatorlink",
|
module: "airflow.sdk",
|
||||||
name: "BaseOperatorLink",
|
name: "BaseOperatorLink",
|
||||||
},
|
},
|
||||||
// airflow.model..DAG
|
// airflow.model..DAG
|
||||||
@@ -284,33 +283,34 @@ fn check_name(checker: &Checker, expr: &Expr, range: TextRange) {
|
|||||||
_ => return,
|
_ => return,
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut diagnostic = Diagnostic::new(
|
let (module, name) = match &replacement {
|
||||||
|
Replacement::AutoImport { module, name } => (module, *name),
|
||||||
|
Replacement::SourceModuleMoved { module, name } => (module, name.as_str()),
|
||||||
|
_ => {
|
||||||
|
checker.report_diagnostic(
|
||||||
|
Airflow3SuggestedUpdate {
|
||||||
|
deprecated: qualified_name.to_string(),
|
||||||
|
replacement: replacement.clone(),
|
||||||
|
},
|
||||||
|
range,
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if is_guarded_by_try_except(expr, module, name, checker.semantic()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let mut diagnostic = checker.report_diagnostic(
|
||||||
Airflow3SuggestedUpdate {
|
Airflow3SuggestedUpdate {
|
||||||
deprecated: qualified_name.to_string(),
|
deprecated: qualified_name.to_string(),
|
||||||
replacement: replacement.clone(),
|
replacement: replacement.clone(),
|
||||||
},
|
},
|
||||||
range,
|
range,
|
||||||
);
|
);
|
||||||
|
if let Some(fix) = generate_import_edit(expr, checker, module, name, range)
|
||||||
let semantic = checker.semantic();
|
.or_else(|| generate_remove_and_runtime_import_edit(expr, checker, module, name))
|
||||||
if let Some((module, name)) = match &replacement {
|
{
|
||||||
Replacement::AutoImport { module, name } => Some((module, *name)),
|
diagnostic.set_fix(fix);
|
||||||
Replacement::SourceModuleMoved { module, name } => Some((module, name.as_str())),
|
|
||||||
_ => None,
|
|
||||||
} {
|
|
||||||
if is_guarded_by_try_except(expr, module, name, semantic) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
diagnostic.try_set_fix(|| {
|
|
||||||
let (import_edit, binding) = checker.importer().get_or_import_symbol(
|
|
||||||
&ImportRequest::import_from(module, name),
|
|
||||||
expr.start(),
|
|
||||||
checker.semantic(),
|
|
||||||
)?;
|
|
||||||
let replacement_edit = Edit::range_replacement(binding, range);
|
|
||||||
Ok(Fix::safe_edits(import_edit, [replacement_edit]))
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
checker.report_diagnostic(diagnostic);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use ruff_diagnostics::{Diagnostic, Violation};
|
use crate::Violation;
|
||||||
use ruff_macros::{ViolationMetadata, derive_message_formats};
|
use ruff_macros::{ViolationMetadata, derive_message_formats};
|
||||||
use ruff_python_ast as ast;
|
use ruff_python_ast as ast;
|
||||||
use ruff_python_ast::Expr;
|
use ruff_python_ast::Expr;
|
||||||
@@ -110,11 +110,10 @@ pub(crate) fn variable_name_task_id(checker: &Checker, targets: &[Expr], value:
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let diagnostic = Diagnostic::new(
|
checker.report_diagnostic(
|
||||||
AirflowVariableNameTaskIdMismatch {
|
AirflowVariableNameTaskIdMismatch {
|
||||||
task_id: task_id.to_string(),
|
task_id: task_id.to_string(),
|
||||||
},
|
},
|
||||||
target.range(),
|
target.range(),
|
||||||
);
|
);
|
||||||
checker.report_diagnostic(diagnostic);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -171,7 +171,7 @@ AIR301_class_attribute.py:42:6: AIR301 [*] `airflow.datasets.manager.DatasetMana
|
|||||||
43 | dm.register_dataset_change()
|
43 | dm.register_dataset_change()
|
||||||
44 | dm.create_datasets()
|
44 | dm.create_datasets()
|
||||||
|
|
|
|
||||||
= help: Use `airflow.assets.manager.AssetManager` instead
|
= help: Use `AssetManager` from `airflow.assets.manager` instead.
|
||||||
|
|
||||||
ℹ Safe fix
|
ℹ Safe fix
|
||||||
19 19 | from airflow.providers_manager import ProvidersManager
|
19 19 | from airflow.providers_manager import ProvidersManager
|
||||||
@@ -302,7 +302,7 @@ AIR301_class_attribute.py:50:11: AIR301 [*] `airflow.lineage.hook.DatasetLineage
|
|||||||
| ^^^^^^^^^^^^^^^^^^ AIR301
|
| ^^^^^^^^^^^^^^^^^^ AIR301
|
||||||
51 | dl_info.dataset
|
51 | dl_info.dataset
|
||||||
|
|
|
|
||||||
= help: Use `airflow.lineage.hook.AssetLineageInfo` instead
|
= help: Use `AssetLineageInfo` from `airflow.lineage.hook` instead.
|
||||||
|
|
||||||
ℹ Safe fix
|
ℹ Safe fix
|
||||||
9 9 | DatasetAny,
|
9 9 | DatasetAny,
|
||||||
|
|||||||
@@ -1,651 +1,294 @@
|
|||||||
---
|
---
|
||||||
source: crates/ruff_linter/src/rules/airflow/mod.rs
|
source: crates/ruff_linter/src/rules/airflow/mod.rs
|
||||||
---
|
---
|
||||||
AIR301_names.py:53:1: AIR301 `airflow.PY36` is removed in Airflow 3.0
|
AIR301_names.py:38:1: AIR301 `airflow.PY36` is removed in Airflow 3.0
|
||||||
|
|
|
|
||||||
52 | # airflow root
|
37 | # airflow root
|
||||||
53 | PY36, PY37, PY38, PY39, PY310, PY311, PY312
|
38 | PY36, PY37, PY38, PY39, PY310, PY311, PY312
|
||||||
| ^^^^ AIR301
|
| ^^^^ AIR301
|
||||||
54 |
|
39 |
|
||||||
55 | # airflow.api_connexion.security
|
40 | # airflow.api_connexion.security
|
||||||
|
|
|
|
||||||
= help: Use `sys.version_info` instead
|
= help: Use `sys.version_info` instead
|
||||||
|
|
||||||
AIR301_names.py:53:7: AIR301 `airflow.PY37` is removed in Airflow 3.0
|
AIR301_names.py:38:7: AIR301 `airflow.PY37` is removed in Airflow 3.0
|
||||||
|
|
|
|
||||||
52 | # airflow root
|
37 | # airflow root
|
||||||
53 | PY36, PY37, PY38, PY39, PY310, PY311, PY312
|
38 | PY36, PY37, PY38, PY39, PY310, PY311, PY312
|
||||||
| ^^^^ AIR301
|
| ^^^^ AIR301
|
||||||
54 |
|
39 |
|
||||||
55 | # airflow.api_connexion.security
|
40 | # airflow.api_connexion.security
|
||||||
|
|
|
|
||||||
= help: Use `sys.version_info` instead
|
= help: Use `sys.version_info` instead
|
||||||
|
|
||||||
AIR301_names.py:53:13: AIR301 `airflow.PY38` is removed in Airflow 3.0
|
AIR301_names.py:38:13: AIR301 `airflow.PY38` is removed in Airflow 3.0
|
||||||
|
|
|
|
||||||
52 | # airflow root
|
37 | # airflow root
|
||||||
53 | PY36, PY37, PY38, PY39, PY310, PY311, PY312
|
38 | PY36, PY37, PY38, PY39, PY310, PY311, PY312
|
||||||
| ^^^^ AIR301
|
| ^^^^ AIR301
|
||||||
54 |
|
39 |
|
||||||
55 | # airflow.api_connexion.security
|
40 | # airflow.api_connexion.security
|
||||||
|
|
|
|
||||||
= help: Use `sys.version_info` instead
|
= help: Use `sys.version_info` instead
|
||||||
|
|
||||||
AIR301_names.py:53:19: AIR301 `airflow.PY39` is removed in Airflow 3.0
|
AIR301_names.py:38:19: AIR301 `airflow.PY39` is removed in Airflow 3.0
|
||||||
|
|
|
|
||||||
52 | # airflow root
|
37 | # airflow root
|
||||||
53 | PY36, PY37, PY38, PY39, PY310, PY311, PY312
|
38 | PY36, PY37, PY38, PY39, PY310, PY311, PY312
|
||||||
| ^^^^ AIR301
|
| ^^^^ AIR301
|
||||||
54 |
|
39 |
|
||||||
55 | # airflow.api_connexion.security
|
40 | # airflow.api_connexion.security
|
||||||
|
|
|
|
||||||
= help: Use `sys.version_info` instead
|
= help: Use `sys.version_info` instead
|
||||||
|
|
||||||
AIR301_names.py:53:25: AIR301 `airflow.PY310` is removed in Airflow 3.0
|
AIR301_names.py:38:25: AIR301 `airflow.PY310` is removed in Airflow 3.0
|
||||||
|
|
|
|
||||||
52 | # airflow root
|
37 | # airflow root
|
||||||
53 | PY36, PY37, PY38, PY39, PY310, PY311, PY312
|
38 | PY36, PY37, PY38, PY39, PY310, PY311, PY312
|
||||||
| ^^^^^ AIR301
|
| ^^^^^ AIR301
|
||||||
54 |
|
39 |
|
||||||
55 | # airflow.api_connexion.security
|
40 | # airflow.api_connexion.security
|
||||||
|
|
|
|
||||||
= help: Use `sys.version_info` instead
|
= help: Use `sys.version_info` instead
|
||||||
|
|
||||||
AIR301_names.py:53:32: AIR301 `airflow.PY311` is removed in Airflow 3.0
|
AIR301_names.py:38:32: AIR301 `airflow.PY311` is removed in Airflow 3.0
|
||||||
|
|
|
|
||||||
52 | # airflow root
|
37 | # airflow root
|
||||||
53 | PY36, PY37, PY38, PY39, PY310, PY311, PY312
|
38 | PY36, PY37, PY38, PY39, PY310, PY311, PY312
|
||||||
| ^^^^^ AIR301
|
| ^^^^^ AIR301
|
||||||
54 |
|
39 |
|
||||||
55 | # airflow.api_connexion.security
|
40 | # airflow.api_connexion.security
|
||||||
|
|
|
|
||||||
= help: Use `sys.version_info` instead
|
= help: Use `sys.version_info` instead
|
||||||
|
|
||||||
AIR301_names.py:53:39: AIR301 `airflow.PY312` is removed in Airflow 3.0
|
AIR301_names.py:38:39: AIR301 `airflow.PY312` is removed in Airflow 3.0
|
||||||
|
|
|
|
||||||
52 | # airflow root
|
37 | # airflow root
|
||||||
53 | PY36, PY37, PY38, PY39, PY310, PY311, PY312
|
38 | PY36, PY37, PY38, PY39, PY310, PY311, PY312
|
||||||
| ^^^^^ AIR301
|
| ^^^^^ AIR301
|
||||||
54 |
|
39 |
|
||||||
55 | # airflow.api_connexion.security
|
40 | # airflow.api_connexion.security
|
||||||
|
|
|
|
||||||
= help: Use `sys.version_info` instead
|
= help: Use `sys.version_info` instead
|
||||||
|
|
||||||
AIR301_names.py:56:1: AIR301 `airflow.api_connexion.security.requires_access` is removed in Airflow 3.0
|
AIR301_names.py:41:1: AIR301 `airflow.api_connexion.security.requires_access` is removed in Airflow 3.0
|
||||||
|
|
|
|
||||||
55 | # airflow.api_connexion.security
|
40 | # airflow.api_connexion.security
|
||||||
56 | requires_access
|
41 | requires_access
|
||||||
| ^^^^^^^^^^^^^^^ AIR301
|
| ^^^^^^^^^^^^^^^ AIR301
|
||||||
|
42 |
|
||||||
|
43 | # airflow.contrib.*
|
||||||
|
|
|
|
||||||
= help: Use `airflow.api_fastapi.core_api.security.requires_access_*` instead
|
= help: Use `airflow.api_fastapi.core_api.security.requires_access_*` instead
|
||||||
|
|
||||||
AIR301_names.py:60:1: AIR301 [*] `airflow.configuration.get` is removed in Airflow 3.0
|
AIR301_names.py:44:1: AIR301 `airflow.contrib.aws_athena_hook.AWSAthenaHook` is removed in Airflow 3.0
|
||||||
|
|
|
|
||||||
59 | # airflow.configuration
|
43 | # airflow.contrib.*
|
||||||
60 | get, getboolean, getfloat, getint, has_option, remove_option, as_dict, set
|
44 | AWSAthenaHook()
|
||||||
| ^^^ AIR301
|
|
||||||
|
|
|
||||||
= help: Use `airflow.configuration.conf.get` instead
|
|
||||||
|
|
||||||
ℹ Safe fix
|
|
||||||
19 19 | has_option,
|
|
||||||
20 20 | remove_option,
|
|
||||||
21 21 | set,
|
|
||||||
22 |+conf,
|
|
||||||
22 23 | )
|
|
||||||
23 24 | from airflow.contrib.aws_athena_hook import AWSAthenaHook
|
|
||||||
24 25 | from airflow.datasets import DatasetAliasEvent
|
|
||||||
--------------------------------------------------------------------------------
|
|
||||||
57 58 |
|
|
||||||
58 59 |
|
|
||||||
59 60 | # airflow.configuration
|
|
||||||
60 |-get, getboolean, getfloat, getint, has_option, remove_option, as_dict, set
|
|
||||||
61 |+conf.get, getboolean, getfloat, getint, has_option, remove_option, as_dict, set
|
|
||||||
61 62 |
|
|
||||||
62 63 |
|
|
||||||
63 64 | # airflow.contrib.*
|
|
||||||
|
|
||||||
AIR301_names.py:60:6: AIR301 [*] `airflow.configuration.getboolean` is removed in Airflow 3.0
|
|
||||||
|
|
|
||||||
59 | # airflow.configuration
|
|
||||||
60 | get, getboolean, getfloat, getint, has_option, remove_option, as_dict, set
|
|
||||||
| ^^^^^^^^^^ AIR301
|
|
||||||
|
|
|
||||||
= help: Use `airflow.configuration.conf.getboolean` instead
|
|
||||||
|
|
||||||
ℹ Safe fix
|
|
||||||
19 19 | has_option,
|
|
||||||
20 20 | remove_option,
|
|
||||||
21 21 | set,
|
|
||||||
22 |+conf,
|
|
||||||
22 23 | )
|
|
||||||
23 24 | from airflow.contrib.aws_athena_hook import AWSAthenaHook
|
|
||||||
24 25 | from airflow.datasets import DatasetAliasEvent
|
|
||||||
--------------------------------------------------------------------------------
|
|
||||||
57 58 |
|
|
||||||
58 59 |
|
|
||||||
59 60 | # airflow.configuration
|
|
||||||
60 |-get, getboolean, getfloat, getint, has_option, remove_option, as_dict, set
|
|
||||||
61 |+get, conf.getboolean, getfloat, getint, has_option, remove_option, as_dict, set
|
|
||||||
61 62 |
|
|
||||||
62 63 |
|
|
||||||
63 64 | # airflow.contrib.*
|
|
||||||
|
|
||||||
AIR301_names.py:60:18: AIR301 [*] `airflow.configuration.getfloat` is removed in Airflow 3.0
|
|
||||||
|
|
|
||||||
59 | # airflow.configuration
|
|
||||||
60 | get, getboolean, getfloat, getint, has_option, remove_option, as_dict, set
|
|
||||||
| ^^^^^^^^ AIR301
|
|
||||||
|
|
|
||||||
= help: Use `airflow.configuration.conf.getfloat` instead
|
|
||||||
|
|
||||||
ℹ Safe fix
|
|
||||||
19 19 | has_option,
|
|
||||||
20 20 | remove_option,
|
|
||||||
21 21 | set,
|
|
||||||
22 |+conf,
|
|
||||||
22 23 | )
|
|
||||||
23 24 | from airflow.contrib.aws_athena_hook import AWSAthenaHook
|
|
||||||
24 25 | from airflow.datasets import DatasetAliasEvent
|
|
||||||
--------------------------------------------------------------------------------
|
|
||||||
57 58 |
|
|
||||||
58 59 |
|
|
||||||
59 60 | # airflow.configuration
|
|
||||||
60 |-get, getboolean, getfloat, getint, has_option, remove_option, as_dict, set
|
|
||||||
61 |+get, getboolean, conf.getfloat, getint, has_option, remove_option, as_dict, set
|
|
||||||
61 62 |
|
|
||||||
62 63 |
|
|
||||||
63 64 | # airflow.contrib.*
|
|
||||||
|
|
||||||
AIR301_names.py:60:28: AIR301 [*] `airflow.configuration.getint` is removed in Airflow 3.0
|
|
||||||
|
|
|
||||||
59 | # airflow.configuration
|
|
||||||
60 | get, getboolean, getfloat, getint, has_option, remove_option, as_dict, set
|
|
||||||
| ^^^^^^ AIR301
|
|
||||||
|
|
|
||||||
= help: Use `airflow.configuration.conf.getint` instead
|
|
||||||
|
|
||||||
ℹ Safe fix
|
|
||||||
19 19 | has_option,
|
|
||||||
20 20 | remove_option,
|
|
||||||
21 21 | set,
|
|
||||||
22 |+conf,
|
|
||||||
22 23 | )
|
|
||||||
23 24 | from airflow.contrib.aws_athena_hook import AWSAthenaHook
|
|
||||||
24 25 | from airflow.datasets import DatasetAliasEvent
|
|
||||||
--------------------------------------------------------------------------------
|
|
||||||
57 58 |
|
|
||||||
58 59 |
|
|
||||||
59 60 | # airflow.configuration
|
|
||||||
60 |-get, getboolean, getfloat, getint, has_option, remove_option, as_dict, set
|
|
||||||
61 |+get, getboolean, getfloat, conf.getint, has_option, remove_option, as_dict, set
|
|
||||||
61 62 |
|
|
||||||
62 63 |
|
|
||||||
63 64 | # airflow.contrib.*
|
|
||||||
|
|
||||||
AIR301_names.py:60:36: AIR301 [*] `airflow.configuration.has_option` is removed in Airflow 3.0
|
|
||||||
|
|
|
||||||
59 | # airflow.configuration
|
|
||||||
60 | get, getboolean, getfloat, getint, has_option, remove_option, as_dict, set
|
|
||||||
| ^^^^^^^^^^ AIR301
|
|
||||||
|
|
|
||||||
= help: Use `airflow.configuration.conf.has_option` instead
|
|
||||||
|
|
||||||
ℹ Safe fix
|
|
||||||
19 19 | has_option,
|
|
||||||
20 20 | remove_option,
|
|
||||||
21 21 | set,
|
|
||||||
22 |+conf,
|
|
||||||
22 23 | )
|
|
||||||
23 24 | from airflow.contrib.aws_athena_hook import AWSAthenaHook
|
|
||||||
24 25 | from airflow.datasets import DatasetAliasEvent
|
|
||||||
--------------------------------------------------------------------------------
|
|
||||||
57 58 |
|
|
||||||
58 59 |
|
|
||||||
59 60 | # airflow.configuration
|
|
||||||
60 |-get, getboolean, getfloat, getint, has_option, remove_option, as_dict, set
|
|
||||||
61 |+get, getboolean, getfloat, getint, conf.has_option, remove_option, as_dict, set
|
|
||||||
61 62 |
|
|
||||||
62 63 |
|
|
||||||
63 64 | # airflow.contrib.*
|
|
||||||
|
|
||||||
AIR301_names.py:60:48: AIR301 [*] `airflow.configuration.remove_option` is removed in Airflow 3.0
|
|
||||||
|
|
|
||||||
59 | # airflow.configuration
|
|
||||||
60 | get, getboolean, getfloat, getint, has_option, remove_option, as_dict, set
|
|
||||||
| ^^^^^^^^^^^^^ AIR301
|
|
||||||
|
|
|
||||||
= help: Use `airflow.configuration.conf.remove_option` instead
|
|
||||||
|
|
||||||
ℹ Safe fix
|
|
||||||
19 19 | has_option,
|
|
||||||
20 20 | remove_option,
|
|
||||||
21 21 | set,
|
|
||||||
22 |+conf,
|
|
||||||
22 23 | )
|
|
||||||
23 24 | from airflow.contrib.aws_athena_hook import AWSAthenaHook
|
|
||||||
24 25 | from airflow.datasets import DatasetAliasEvent
|
|
||||||
--------------------------------------------------------------------------------
|
|
||||||
57 58 |
|
|
||||||
58 59 |
|
|
||||||
59 60 | # airflow.configuration
|
|
||||||
60 |-get, getboolean, getfloat, getint, has_option, remove_option, as_dict, set
|
|
||||||
61 |+get, getboolean, getfloat, getint, has_option, conf.remove_option, as_dict, set
|
|
||||||
61 62 |
|
|
||||||
62 63 |
|
|
||||||
63 64 | # airflow.contrib.*
|
|
||||||
|
|
||||||
AIR301_names.py:60:63: AIR301 [*] `airflow.configuration.as_dict` is removed in Airflow 3.0
|
|
||||||
|
|
|
||||||
59 | # airflow.configuration
|
|
||||||
60 | get, getboolean, getfloat, getint, has_option, remove_option, as_dict, set
|
|
||||||
| ^^^^^^^ AIR301
|
|
||||||
|
|
|
||||||
= help: Use `airflow.configuration.conf.as_dict` instead
|
|
||||||
|
|
||||||
ℹ Safe fix
|
|
||||||
19 19 | has_option,
|
|
||||||
20 20 | remove_option,
|
|
||||||
21 21 | set,
|
|
||||||
22 |+conf,
|
|
||||||
22 23 | )
|
|
||||||
23 24 | from airflow.contrib.aws_athena_hook import AWSAthenaHook
|
|
||||||
24 25 | from airflow.datasets import DatasetAliasEvent
|
|
||||||
--------------------------------------------------------------------------------
|
|
||||||
57 58 |
|
|
||||||
58 59 |
|
|
||||||
59 60 | # airflow.configuration
|
|
||||||
60 |-get, getboolean, getfloat, getint, has_option, remove_option, as_dict, set
|
|
||||||
61 |+get, getboolean, getfloat, getint, has_option, remove_option, conf.as_dict, set
|
|
||||||
61 62 |
|
|
||||||
62 63 |
|
|
||||||
63 64 | # airflow.contrib.*
|
|
||||||
|
|
||||||
AIR301_names.py:60:72: AIR301 [*] `airflow.configuration.set` is removed in Airflow 3.0
|
|
||||||
|
|
|
||||||
59 | # airflow.configuration
|
|
||||||
60 | get, getboolean, getfloat, getint, has_option, remove_option, as_dict, set
|
|
||||||
| ^^^ AIR301
|
|
||||||
|
|
|
||||||
= help: Use `airflow.configuration.conf.set` instead
|
|
||||||
|
|
||||||
ℹ Safe fix
|
|
||||||
19 19 | has_option,
|
|
||||||
20 20 | remove_option,
|
|
||||||
21 21 | set,
|
|
||||||
22 |+conf,
|
|
||||||
22 23 | )
|
|
||||||
23 24 | from airflow.contrib.aws_athena_hook import AWSAthenaHook
|
|
||||||
24 25 | from airflow.datasets import DatasetAliasEvent
|
|
||||||
--------------------------------------------------------------------------------
|
|
||||||
57 58 |
|
|
||||||
58 59 |
|
|
||||||
59 60 | # airflow.configuration
|
|
||||||
60 |-get, getboolean, getfloat, getint, has_option, remove_option, as_dict, set
|
|
||||||
61 |+get, getboolean, getfloat, getint, has_option, remove_option, as_dict, conf.set
|
|
||||||
61 62 |
|
|
||||||
62 63 |
|
|
||||||
63 64 | # airflow.contrib.*
|
|
||||||
|
|
||||||
AIR301_names.py:64:1: AIR301 `airflow.contrib.aws_athena_hook.AWSAthenaHook` is removed in Airflow 3.0
|
|
||||||
|
|
|
||||||
63 | # airflow.contrib.*
|
|
||||||
64 | AWSAthenaHook()
|
|
||||||
| ^^^^^^^^^^^^^ AIR301
|
| ^^^^^^^^^^^^^ AIR301
|
||||||
|
|
|
|
||||||
= help: The whole `airflow.contrib` module has been removed.
|
= help: The whole `airflow.contrib` module has been removed.
|
||||||
|
|
||||||
AIR301_names.py:68:1: AIR301 `airflow.datasets.DatasetAliasEvent` is removed in Airflow 3.0
|
AIR301_names.py:48:1: AIR301 `airflow.datasets.DatasetAliasEvent` is removed in Airflow 3.0
|
||||||
|
|
|
|
||||||
67 | # airflow.datasets
|
47 | # airflow.datasets
|
||||||
68 | DatasetAliasEvent()
|
48 | DatasetAliasEvent()
|
||||||
| ^^^^^^^^^^^^^^^^^ AIR301
|
| ^^^^^^^^^^^^^^^^^ AIR301
|
||||||
|
|
|
|
||||||
|
|
||||||
AIR301_names.py:72:1: AIR301 `airflow.hooks.base_hook.BaseHook` is removed in Airflow 3.0
|
AIR301_names.py:52:1: AIR301 `airflow.operators.subdag.SubDagOperator` is removed in Airflow 3.0
|
||||||
|
|
|
|
||||||
71 | # airflow.hooks
|
51 | # airflow.operators.subdag.*
|
||||||
72 | BaseHook()
|
52 | SubDagOperator()
|
||||||
| ^^^^^^^^ AIR301
|
|
||||||
|
|
|
||||||
= help: Use `airflow.hooks.base.BaseHook` instead
|
|
||||||
|
|
||||||
AIR301_names.py:76:1: AIR301 `airflow.operators.subdag.SubDagOperator` is removed in Airflow 3.0
|
|
||||||
|
|
|
||||||
75 | # airflow.operators.subdag.*
|
|
||||||
76 | SubDagOperator()
|
|
||||||
| ^^^^^^^^^^^^^^ AIR301
|
| ^^^^^^^^^^^^^^ AIR301
|
||||||
|
|
|
|
||||||
= help: The whole `airflow.subdag` module has been removed.
|
= help: The whole `airflow.subdag` module has been removed.
|
||||||
|
|
||||||
AIR301_names.py:85:1: AIR301 `airflow.sensors.base_sensor_operator.BaseSensorOperator` is removed in Airflow 3.0
|
AIR301_names.py:61:1: AIR301 `airflow.triggers.external_task.TaskStateTrigger` is removed in Airflow 3.0
|
||||||
|
|
|
|
||||||
84 | # airflow.sensors.base_sensor_operator
|
60 | # airflow.triggers.external_task
|
||||||
85 | BaseSensorOperator()
|
61 | TaskStateTrigger()
|
||||||
| ^^^^^^^^^^^^^^^^^^ AIR301
|
|
||||||
|
|
|
||||||
= help: Use `airflow.sdk.bases.sensor.BaseSensorOperator` instead
|
|
||||||
|
|
||||||
AIR301_names.py:89:1: AIR301 `airflow.triggers.external_task.TaskStateTrigger` is removed in Airflow 3.0
|
|
||||||
|
|
|
||||||
88 | # airflow.triggers.external_task
|
|
||||||
89 | TaskStateTrigger()
|
|
||||||
| ^^^^^^^^^^^^^^^^ AIR301
|
| ^^^^^^^^^^^^^^^^ AIR301
|
||||||
90 |
|
62 |
|
||||||
91 | # airflow.utils.date
|
63 | # airflow.utils.date
|
||||||
|
|
|
|
||||||
|
|
||||||
AIR301_names.py:92:1: AIR301 `airflow.utils.dates.date_range` is removed in Airflow 3.0
|
AIR301_names.py:64:1: AIR301 `airflow.utils.dates.date_range` is removed in Airflow 3.0
|
||||||
|
|
|
|
||||||
91 | # airflow.utils.date
|
63 | # airflow.utils.date
|
||||||
92 | dates.date_range
|
64 | dates.date_range
|
||||||
| ^^^^^^^^^^^^^^^^ AIR301
|
| ^^^^^^^^^^^^^^^^ AIR301
|
||||||
93 | dates.days_ago
|
65 | dates.days_ago
|
||||||
|
|
|
|
||||||
|
|
||||||
AIR301_names.py:93:1: AIR301 `airflow.utils.dates.days_ago` is removed in Airflow 3.0
|
AIR301_names.py:65:1: AIR301 `airflow.utils.dates.days_ago` is removed in Airflow 3.0
|
||||||
|
|
|
|
||||||
91 | # airflow.utils.date
|
63 | # airflow.utils.date
|
||||||
92 | dates.date_range
|
64 | dates.date_range
|
||||||
93 | dates.days_ago
|
65 | dates.days_ago
|
||||||
| ^^^^^^^^^^^^^^ AIR301
|
| ^^^^^^^^^^^^^^ AIR301
|
||||||
94 |
|
66 |
|
||||||
95 | date_range
|
67 | date_range
|
||||||
|
|
|
|
||||||
= help: Use `pendulum.today('UTC').add(days=-N, ...)` instead
|
= help: Use `pendulum.today('UTC').add(days=-N, ...)` instead
|
||||||
|
|
||||||
AIR301_names.py:95:1: AIR301 `airflow.utils.dates.date_range` is removed in Airflow 3.0
|
AIR301_names.py:67:1: AIR301 `airflow.utils.dates.date_range` is removed in Airflow 3.0
|
||||||
|
|
|
|
||||||
93 | dates.days_ago
|
65 | dates.days_ago
|
||||||
94 |
|
66 |
|
||||||
95 | date_range
|
67 | date_range
|
||||||
| ^^^^^^^^^^ AIR301
|
| ^^^^^^^^^^ AIR301
|
||||||
96 | days_ago
|
68 | days_ago
|
||||||
97 | infer_time_unit
|
69 | infer_time_unit
|
||||||
|
|
|
|
||||||
|
|
||||||
AIR301_names.py:96:1: AIR301 `airflow.utils.dates.days_ago` is removed in Airflow 3.0
|
AIR301_names.py:68:1: AIR301 `airflow.utils.dates.days_ago` is removed in Airflow 3.0
|
||||||
|
|
|
|
||||||
95 | date_range
|
67 | date_range
|
||||||
96 | days_ago
|
68 | days_ago
|
||||||
| ^^^^^^^^ AIR301
|
| ^^^^^^^^ AIR301
|
||||||
97 | infer_time_unit
|
69 | infer_time_unit
|
||||||
98 | parse_execution_date
|
70 | parse_execution_date
|
||||||
|
|
|
|
||||||
= help: Use `pendulum.today('UTC').add(days=-N, ...)` instead
|
= help: Use `pendulum.today('UTC').add(days=-N, ...)` instead
|
||||||
|
|
||||||
AIR301_names.py:97:1: AIR301 `airflow.utils.dates.infer_time_unit` is removed in Airflow 3.0
|
AIR301_names.py:69:1: AIR301 `airflow.utils.dates.infer_time_unit` is removed in Airflow 3.0
|
||||||
|
|
|
|
||||||
95 | date_range
|
67 | date_range
|
||||||
96 | days_ago
|
68 | days_ago
|
||||||
97 | infer_time_unit
|
69 | infer_time_unit
|
||||||
| ^^^^^^^^^^^^^^^ AIR301
|
| ^^^^^^^^^^^^^^^ AIR301
|
||||||
98 | parse_execution_date
|
70 | parse_execution_date
|
||||||
99 | round_time
|
71 | round_time
|
||||||
|
|
|
|
||||||
|
|
||||||
AIR301_names.py:98:1: AIR301 `airflow.utils.dates.parse_execution_date` is removed in Airflow 3.0
|
AIR301_names.py:70:1: AIR301 `airflow.utils.dates.parse_execution_date` is removed in Airflow 3.0
|
||||||
|
|
|
|
||||||
96 | days_ago
|
68 | days_ago
|
||||||
97 | infer_time_unit
|
69 | infer_time_unit
|
||||||
98 | parse_execution_date
|
70 | parse_execution_date
|
||||||
| ^^^^^^^^^^^^^^^^^^^^ AIR301
|
| ^^^^^^^^^^^^^^^^^^^^ AIR301
|
||||||
99 | round_time
|
71 | round_time
|
||||||
100 | scale_time_units
|
72 | scale_time_units
|
||||||
|
|
|
|
||||||
|
|
||||||
AIR301_names.py:99:1: AIR301 `airflow.utils.dates.round_time` is removed in Airflow 3.0
|
AIR301_names.py:71:1: AIR301 `airflow.utils.dates.round_time` is removed in Airflow 3.0
|
||||||
|
|
|
||||||
|
69 | infer_time_unit
|
||||||
|
70 | parse_execution_date
|
||||||
|
71 | round_time
|
||||||
|
| ^^^^^^^^^^ AIR301
|
||||||
|
72 | scale_time_units
|
||||||
|
|
|
||||||
|
|
||||||
|
AIR301_names.py:72:1: AIR301 `airflow.utils.dates.scale_time_units` is removed in Airflow 3.0
|
||||||
|
|
|
||||||
|
70 | parse_execution_date
|
||||||
|
71 | round_time
|
||||||
|
72 | scale_time_units
|
||||||
|
| ^^^^^^^^^^^^^^^^ AIR301
|
||||||
|
73 |
|
||||||
|
74 | # This one was not deprecated.
|
||||||
|
|
|
||||||
|
|
||||||
|
AIR301_names.py:79:1: AIR301 `airflow.utils.dag_cycle_tester.test_cycle` is removed in Airflow 3.0
|
||||||
|
|
|
||||||
|
78 | # airflow.utils.dag_cycle_tester
|
||||||
|
79 | test_cycle
|
||||||
|
| ^^^^^^^^^^ AIR301
|
||||||
|
|
|
||||||
|
|
||||||
|
AIR301_names.py:83:1: AIR301 `airflow.utils.db.create_session` is removed in Airflow 3.0
|
||||||
|
|
|
||||||
|
82 | # airflow.utils.db
|
||||||
|
83 | create_session
|
||||||
|
| ^^^^^^^^^^^^^^ AIR301
|
||||||
|
84 |
|
||||||
|
85 | # airflow.utils.decorators
|
||||||
|
|
|
||||||
|
|
||||||
|
AIR301_names.py:86:1: AIR301 `airflow.utils.decorators.apply_defaults` is removed in Airflow 3.0
|
||||||
|
|
|
||||||
|
85 | # airflow.utils.decorators
|
||||||
|
86 | apply_defaults
|
||||||
|
| ^^^^^^^^^^^^^^ AIR301
|
||||||
|
87 |
|
||||||
|
88 | # airflow.utils.file
|
||||||
|
|
|
||||||
|
= help: `apply_defaults` is now unconditionally done and can be safely removed.
|
||||||
|
|
||||||
|
AIR301_names.py:89:1: AIR301 `airflow.utils.file.mkdirs` is removed in Airflow 3.0
|
||||||
|
|
|
||||||
|
88 | # airflow.utils.file
|
||||||
|
89 | mkdirs
|
||||||
|
| ^^^^^^ AIR301
|
||||||
|
|
|
||||||
|
= help: Use `pathlib.Path({path}).mkdir` instead
|
||||||
|
|
||||||
|
AIR301_names.py:93:1: AIR301 `airflow.utils.state.SHUTDOWN` is removed in Airflow 3.0
|
||||||
|
|
|
||||||
|
92 | # airflow.utils.state
|
||||||
|
93 | SHUTDOWN
|
||||||
|
| ^^^^^^^^ AIR301
|
||||||
|
94 | terminating_states
|
||||||
|
|
|
||||||
|
|
||||||
|
AIR301_names.py:94:1: AIR301 `airflow.utils.state.terminating_states` is removed in Airflow 3.0
|
||||||
|
|
|
||||||
|
92 | # airflow.utils.state
|
||||||
|
93 | SHUTDOWN
|
||||||
|
94 | terminating_states
|
||||||
|
| ^^^^^^^^^^^^^^^^^^ AIR301
|
||||||
|
95 |
|
||||||
|
96 | # airflow.utils.trigger_rule
|
||||||
|
|
|
||||||
|
|
||||||
|
AIR301_names.py:97:1: AIR301 `airflow.utils.trigger_rule.TriggerRule.DUMMY` is removed in Airflow 3.0
|
||||||
|
|
|
||||||
|
96 | # airflow.utils.trigger_rule
|
||||||
|
97 | TriggerRule.DUMMY
|
||||||
|
| ^^^^^^^^^^^^^^^^^ AIR301
|
||||||
|
98 | TriggerRule.NONE_FAILED_OR_SKIPPED
|
||||||
|
|
|
||||||
|
|
||||||
|
AIR301_names.py:98:1: AIR301 `airflow.utils.trigger_rule.TriggerRule.NONE_FAILED_OR_SKIPPED` is removed in Airflow 3.0
|
||||||
|
|
|
||||||
|
96 | # airflow.utils.trigger_rule
|
||||||
|
97 | TriggerRule.DUMMY
|
||||||
|
98 | TriggerRule.NONE_FAILED_OR_SKIPPED
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ AIR301
|
||||||
|
|
|
||||||
|
|
||||||
|
AIR301_names.py:102:1: AIR301 `airflow.www.auth.has_access` is removed in Airflow 3.0
|
||||||
|
|
|
|
||||||
97 | infer_time_unit
|
101 | # airflow.www.auth
|
||||||
98 | parse_execution_date
|
102 | has_access
|
||||||
99 | round_time
|
|
||||||
| ^^^^^^^^^^ AIR301
|
| ^^^^^^^^^^ AIR301
|
||||||
100 | scale_time_units
|
103 | has_access_dataset
|
||||||
|
|
|
|
||||||
|
|
||||||
AIR301_names.py:100:1: AIR301 `airflow.utils.dates.scale_time_units` is removed in Airflow 3.0
|
AIR301_names.py:103:1: AIR301 `airflow.www.auth.has_access_dataset` is removed in Airflow 3.0
|
||||||
|
|
|
|
||||||
98 | parse_execution_date
|
101 | # airflow.www.auth
|
||||||
99 | round_time
|
102 | has_access
|
||||||
100 | scale_time_units
|
103 | has_access_dataset
|
||||||
| ^^^^^^^^^^^^^^^^ AIR301
|
|
||||||
101 |
|
|
||||||
102 | # This one was not deprecated.
|
|
||||||
|
|
|
||||||
|
|
||||||
AIR301_names.py:107:1: AIR301 `airflow.utils.dag_cycle_tester.test_cycle` is removed in Airflow 3.0
|
|
||||||
|
|
|
||||||
106 | # airflow.utils.dag_cycle_tester
|
|
||||||
107 | test_cycle
|
|
||||||
| ^^^^^^^^^^ AIR301
|
|
||||||
|
|
|
||||||
|
|
||||||
AIR301_names.py:111:1: AIR301 `airflow.utils.db.create_session` is removed in Airflow 3.0
|
|
||||||
|
|
|
||||||
110 | # airflow.utils.db
|
|
||||||
111 | create_session
|
|
||||||
| ^^^^^^^^^^^^^^ AIR301
|
|
||||||
112 |
|
|
||||||
113 | # airflow.utils.decorators
|
|
||||||
|
|
|
||||||
|
|
||||||
AIR301_names.py:114:1: AIR301 `airflow.utils.decorators.apply_defaults` is removed in Airflow 3.0
|
|
||||||
|
|
|
||||||
113 | # airflow.utils.decorators
|
|
||||||
114 | apply_defaults
|
|
||||||
| ^^^^^^^^^^^^^^ AIR301
|
|
||||||
115 |
|
|
||||||
116 | # airflow.utils.file
|
|
||||||
|
|
|
||||||
= help: `apply_defaults` is now unconditionally done and can be safely removed.
|
|
||||||
|
|
||||||
AIR301_names.py:117:1: AIR301 `airflow.utils.file.TemporaryDirectory` is removed in Airflow 3.0
|
|
||||||
|
|
|
||||||
116 | # airflow.utils.file
|
|
||||||
117 | TemporaryDirectory()
|
|
||||||
| ^^^^^^^^^^^^^^^^^^ AIR301
|
| ^^^^^^^^^^^^^^^^^^ AIR301
|
||||||
118 | mkdirs
|
104 |
|
||||||
|
|
105 | # airflow.www.utils
|
||||||
= help: Use `tempfile.TemporaryDirectory` instead
|
|
||||||
|
|
||||||
AIR301_names.py:118:1: AIR301 `airflow.utils.file.mkdirs` is removed in Airflow 3.0
|
|
||||||
|
|
|
||||||
116 | # airflow.utils.file
|
|
||||||
117 | TemporaryDirectory()
|
|
||||||
118 | mkdirs
|
|
||||||
| ^^^^^^ AIR301
|
|
||||||
119 |
|
|
||||||
120 | # airflow.utils.helpers
|
|
||||||
|
|
|
||||||
= help: Use `pathlib.Path({path}).mkdir` instead
|
|
||||||
|
|
||||||
AIR301_names.py:121:1: AIR301 [*] `airflow.utils.helpers.chain` is removed in Airflow 3.0
|
|
||||||
|
|
|
||||||
120 | # airflow.utils.helpers
|
|
||||||
121 | helper_chain
|
|
||||||
| ^^^^^^^^^^^^ AIR301
|
|
||||||
122 | helper_cross_downstream
|
|
||||||
|
|
|
||||||
= help: Use `airflow.sdk.chain` instead
|
|
||||||
|
|
||||||
ℹ Safe fix
|
|
||||||
48 48 | from airflow.utils.trigger_rule import TriggerRule
|
|
||||||
49 49 | from airflow.www.auth import has_access
|
|
||||||
50 50 | from airflow.www.utils import get_sensitive_variables_fields, should_hide_value_for_key
|
|
||||||
51 |+from airflow.sdk import chain
|
|
||||||
51 52 |
|
|
||||||
52 53 | # airflow root
|
|
||||||
53 54 | PY36, PY37, PY38, PY39, PY310, PY311, PY312
|
|
||||||
--------------------------------------------------------------------------------
|
|
||||||
118 119 | mkdirs
|
|
||||||
119 120 |
|
|
||||||
120 121 | # airflow.utils.helpers
|
|
||||||
121 |-helper_chain
|
|
||||||
122 |+chain
|
|
||||||
122 123 | helper_cross_downstream
|
|
||||||
123 124 |
|
|
||||||
124 125 | # airflow.utils.log
|
|
||||||
|
|
||||||
AIR301_names.py:122:1: AIR301 [*] `airflow.utils.helpers.cross_downstream` is removed in Airflow 3.0
|
|
||||||
|
|
|
||||||
120 | # airflow.utils.helpers
|
|
||||||
121 | helper_chain
|
|
||||||
122 | helper_cross_downstream
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^ AIR301
|
|
||||||
123 |
|
|
||||||
124 | # airflow.utils.log
|
|
||||||
|
|
|
||||||
= help: Use `airflow.sdk.cross_downstream` instead
|
|
||||||
|
|
||||||
ℹ Safe fix
|
|
||||||
48 48 | from airflow.utils.trigger_rule import TriggerRule
|
|
||||||
49 49 | from airflow.www.auth import has_access
|
|
||||||
50 50 | from airflow.www.utils import get_sensitive_variables_fields, should_hide_value_for_key
|
|
||||||
51 |+from airflow.sdk import cross_downstream
|
|
||||||
51 52 |
|
|
||||||
52 53 | # airflow root
|
|
||||||
53 54 | PY36, PY37, PY38, PY39, PY310, PY311, PY312
|
|
||||||
--------------------------------------------------------------------------------
|
|
||||||
119 120 |
|
|
||||||
120 121 | # airflow.utils.helpers
|
|
||||||
121 122 | helper_chain
|
|
||||||
122 |-helper_cross_downstream
|
|
||||||
123 |+cross_downstream
|
|
||||||
123 124 |
|
|
||||||
124 125 | # airflow.utils.log
|
|
||||||
125 126 | secrets_masker
|
|
||||||
|
|
||||||
AIR301_names.py:125:1: AIR301 `airflow.utils.log.secrets_masker` is removed in Airflow 3.0
|
|
||||||
|
|
|
||||||
124 | # airflow.utils.log
|
|
||||||
125 | secrets_masker
|
|
||||||
| ^^^^^^^^^^^^^^ AIR301
|
|
||||||
126 |
|
|
||||||
127 | # airflow.utils.state
|
|
||||||
|
|
|
||||||
= help: Use `airflow.sdk.execution_time.secrets_masker` instead
|
|
||||||
|
|
||||||
AIR301_names.py:128:1: AIR301 `airflow.utils.state.SHUTDOWN` is removed in Airflow 3.0
|
|
||||||
|
|
|
||||||
127 | # airflow.utils.state
|
|
||||||
128 | SHUTDOWN
|
|
||||||
| ^^^^^^^^ AIR301
|
|
||||||
129 | terminating_states
|
|
||||||
|
|
|
|
||||||
|
|
||||||
AIR301_names.py:129:1: AIR301 `airflow.utils.state.terminating_states` is removed in Airflow 3.0
|
AIR301_names.py:106:1: AIR301 `airflow.www.utils.get_sensitive_variables_fields` is removed in Airflow 3.0
|
||||||
|
|
|
|
||||||
127 | # airflow.utils.state
|
105 | # airflow.www.utils
|
||||||
128 | SHUTDOWN
|
106 | get_sensitive_variables_fields
|
||||||
129 | terminating_states
|
|
||||||
| ^^^^^^^^^^^^^^^^^^ AIR301
|
|
||||||
130 |
|
|
||||||
131 | # airflow.utils.trigger_rule
|
|
||||||
|
|
|
||||||
|
|
||||||
AIR301_names.py:132:1: AIR301 `airflow.utils.trigger_rule.TriggerRule.DUMMY` is removed in Airflow 3.0
|
|
||||||
|
|
|
||||||
131 | # airflow.utils.trigger_rule
|
|
||||||
132 | TriggerRule.DUMMY
|
|
||||||
| ^^^^^^^^^^^^^^^^^ AIR301
|
|
||||||
133 | TriggerRule.NONE_FAILED_OR_SKIPPED
|
|
||||||
|
|
|
||||||
|
|
||||||
AIR301_names.py:133:1: AIR301 `airflow.utils.trigger_rule.TriggerRule.NONE_FAILED_OR_SKIPPED` is removed in Airflow 3.0
|
|
||||||
|
|
|
||||||
131 | # airflow.utils.trigger_rule
|
|
||||||
132 | TriggerRule.DUMMY
|
|
||||||
133 | TriggerRule.NONE_FAILED_OR_SKIPPED
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ AIR301
|
|
||||||
|
|
|
||||||
|
|
||||||
AIR301_names.py:137:1: AIR301 `airflow.www.auth.has_access` is removed in Airflow 3.0
|
|
||||||
|
|
|
||||||
136 | # airflow.www.auth
|
|
||||||
137 | has_access
|
|
||||||
| ^^^^^^^^^^ AIR301
|
|
||||||
138 |
|
|
||||||
139 | # airflow.www.utils
|
|
||||||
|
|
|
||||||
|
|
||||||
AIR301_names.py:140:1: AIR301 `airflow.www.utils.get_sensitive_variables_fields` is removed in Airflow 3.0
|
|
||||||
|
|
|
||||||
139 | # airflow.www.utils
|
|
||||||
140 | get_sensitive_variables_fields
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ AIR301
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ AIR301
|
||||||
141 | should_hide_value_for_key
|
107 | should_hide_value_for_key
|
||||||
|
|
|
|
||||||
|
|
||||||
AIR301_names.py:141:1: AIR301 `airflow.www.utils.should_hide_value_for_key` is removed in Airflow 3.0
|
AIR301_names.py:107:1: AIR301 `airflow.www.utils.should_hide_value_for_key` is removed in Airflow 3.0
|
||||||
|
|
|
|
||||||
139 | # airflow.www.utils
|
105 | # airflow.www.utils
|
||||||
140 | get_sensitive_variables_fields
|
106 | get_sensitive_variables_fields
|
||||||
141 | should_hide_value_for_key
|
107 | should_hide_value_for_key
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^ AIR301
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^ AIR301
|
||||||
142 |
|
|
||||||
143 | # airflow.operators.python
|
|
||||||
|
|
|
|
||||||
|
|
||||||
AIR301_names.py:146:1: AIR301 `airflow.operators.python.get_current_context` is removed in Airflow 3.0
|
|
||||||
|
|
|
||||||
144 | from airflow.operators.python import get_current_context
|
|
||||||
145 |
|
|
||||||
146 | get_current_context()
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^ AIR301
|
|
||||||
147 |
|
|
||||||
148 | # airflow.providers.mysql
|
|
||||||
|
|
|
||||||
= help: Use `airflow.sdk.get_current_context` instead
|
|
||||||
|
|
||||||
AIR301_names.py:151:1: AIR301 `airflow.providers.mysql.datasets.mysql.sanitize_uri` is removed in Airflow 3.0
|
|
||||||
|
|
|
||||||
149 | from airflow.providers.mysql.datasets.mysql import sanitize_uri
|
|
||||||
150 |
|
|
||||||
151 | sanitize_uri
|
|
||||||
| ^^^^^^^^^^^^ AIR301
|
|
||||||
152 |
|
|
||||||
153 | # airflow.providers.postgres
|
|
||||||
|
|
|
||||||
= help: Use `airflow.providers.mysql.assets.mysql.sanitize_uri` instead
|
|
||||||
|
|
||||||
AIR301_names.py:156:1: AIR301 `airflow.providers.postgres.datasets.postgres.sanitize_uri` is removed in Airflow 3.0
|
|
||||||
|
|
|
||||||
154 | from airflow.providers.postgres.datasets.postgres import sanitize_uri
|
|
||||||
155 |
|
|
||||||
156 | sanitize_uri
|
|
||||||
| ^^^^^^^^^^^^ AIR301
|
|
||||||
157 |
|
|
||||||
158 | # airflow.providers.trino
|
|
||||||
|
|
|
||||||
= help: Use `airflow.providers.postgres.assets.postgres.sanitize_uri` instead
|
|
||||||
|
|
||||||
AIR301_names.py:161:1: AIR301 `airflow.providers.trino.datasets.trino.sanitize_uri` is removed in Airflow 3.0
|
|
||||||
|
|
|
||||||
159 | from airflow.providers.trino.datasets.trino import sanitize_uri
|
|
||||||
160 |
|
|
||||||
161 | sanitize_uri
|
|
||||||
| ^^^^^^^^^^^^ AIR301
|
|
||||||
162 |
|
|
||||||
163 | # airflow.notifications.basenotifier
|
|
||||||
|
|
|
||||||
= help: Use `airflow.providers.trino.assets.trino.sanitize_uri` instead
|
|
||||||
|
|
||||||
AIR301_names.py:166:1: AIR301 `airflow.notifications.basenotifier.BaseNotifier` is removed in Airflow 3.0
|
|
||||||
|
|
|
||||||
164 | from airflow.notifications.basenotifier import BaseNotifier
|
|
||||||
165 |
|
|
||||||
166 | BaseNotifier()
|
|
||||||
| ^^^^^^^^^^^^ AIR301
|
|
||||||
167 |
|
|
||||||
168 | # airflow.auth.manager
|
|
||||||
|
|
|
||||||
= help: Use `airflow.sdk.bases.notifier.BaseNotifier` instead
|
|
||||||
|
|
||||||
AIR301_names.py:171:1: AIR301 `airflow.auth.managers.base_auth_manager.BaseAuthManager` is removed in Airflow 3.0
|
|
||||||
|
|
|
||||||
169 | from airflow.auth.managers.base_auth_manager import BaseAuthManager
|
|
||||||
170 |
|
|
||||||
171 | BaseAuthManager()
|
|
||||||
| ^^^^^^^^^^^^^^^ AIR301
|
|
||||||
|
|
|
||||||
= help: Use `airflow.api_fastapi.auth.managers.base_auth_manager.BaseAuthManager` instead
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,216 +1,243 @@
|
|||||||
---
|
---
|
||||||
source: crates/ruff_linter/src/rules/airflow/mod.rs
|
source: crates/ruff_linter/src/rules/airflow/mod.rs
|
||||||
---
|
---
|
||||||
AIR301_provider_names_fix.py:25:1: AIR301 [*] `airflow.providers.amazon.aws.auth_manager.avp.entities.AvpEntities.DATASET` is removed in Airflow 3.0
|
AIR301_provider_names_fix.py:11:1: AIR301 [*] `airflow.providers.amazon.aws.auth_manager.avp.entities.AvpEntities.DATASET` is removed in Airflow 3.0
|
||||||
|
|
|
|
||||||
23 | )
|
9 | from airflow.security.permissions import RESOURCE_DATASET
|
||||||
24 |
|
10 |
|
||||||
25 | AvpEntities.DATASET
|
11 | AvpEntities.DATASET
|
||||||
| ^^^^^^^^^^^^^^^^^^^ AIR301
|
| ^^^^^^^^^^^^^^^^^^^ AIR301
|
||||||
26 |
|
12 |
|
||||||
27 | s3_create_dataset()
|
13 | # airflow.providers.openlineage.utils.utils
|
||||||
|
|
|
|
||||||
= help: Use `airflow.providers.amazon.aws.auth_manager.avp.entities.AvpEntities.ASSET` instead
|
= help: Use `AvpEntities.ASSET` from `airflow.providers.amazon.aws.auth_manager.avp.entities` instead.
|
||||||
|
|
||||||
ℹ Safe fix
|
ℹ Safe fix
|
||||||
22 22 | translate_airflow_dataset,
|
8 8 | from airflow.secrets.local_filesystem import load_connections
|
||||||
23 23 | )
|
9 9 | from airflow.security.permissions import RESOURCE_DATASET
|
||||||
24 24 |
|
10 10 |
|
||||||
25 |-AvpEntities.DATASET
|
11 |-AvpEntities.DATASET
|
||||||
25 |+AvpEntities.ASSET
|
11 |+AvpEntities
|
||||||
26 26 |
|
12 12 |
|
||||||
27 27 | s3_create_dataset()
|
13 13 | # airflow.providers.openlineage.utils.utils
|
||||||
28 28 | s3_convert_dataset_to_openlineage()
|
14 14 | DatasetInfo()
|
||||||
|
|
||||||
AIR301_provider_names_fix.py:27:1: AIR301 [*] `airflow.providers.amazon.aws.datasets.s3.create_dataset` is removed in Airflow 3.0
|
AIR301_provider_names_fix.py:14:1: AIR301 [*] `airflow.providers.openlineage.utils.utils.DatasetInfo` is removed in Airflow 3.0
|
||||||
|
|
|
|
||||||
25 | AvpEntities.DATASET
|
13 | # airflow.providers.openlineage.utils.utils
|
||||||
26 |
|
14 | DatasetInfo()
|
||||||
27 | s3_create_dataset()
|
|
||||||
| ^^^^^^^^^^^^^^^^^ AIR301
|
|
||||||
28 | s3_convert_dataset_to_openlineage()
|
|
||||||
|
|
|
||||||
= help: Use `airflow.providers.amazon.aws.assets.s3.create_asset` instead
|
|
||||||
|
|
||||||
ℹ Safe fix
|
|
||||||
21 21 | DatasetInfo,
|
|
||||||
22 22 | translate_airflow_dataset,
|
|
||||||
23 23 | )
|
|
||||||
24 |+from airflow.providers.amazon.aws.assets.s3 import create_asset
|
|
||||||
24 25 |
|
|
||||||
25 26 | AvpEntities.DATASET
|
|
||||||
26 27 |
|
|
||||||
27 |-s3_create_dataset()
|
|
||||||
28 |+create_asset()
|
|
||||||
28 29 | s3_convert_dataset_to_openlineage()
|
|
||||||
29 30 |
|
|
||||||
30 31 | io_create_dataset()
|
|
||||||
|
|
||||||
AIR301_provider_names_fix.py:28:1: AIR301 [*] `airflow.providers.amazon.aws.datasets.s3.convert_dataset_to_openlineage` is removed in Airflow 3.0
|
|
||||||
|
|
|
||||||
27 | s3_create_dataset()
|
|
||||||
28 | s3_convert_dataset_to_openlineage()
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ AIR301
|
|
||||||
29 |
|
|
||||||
30 | io_create_dataset()
|
|
||||||
|
|
|
||||||
= help: Use `airflow.providers.amazon.aws.assets.s3.convert_asset_to_openlineage` instead
|
|
||||||
|
|
||||||
ℹ Safe fix
|
|
||||||
21 21 | DatasetInfo,
|
|
||||||
22 22 | translate_airflow_dataset,
|
|
||||||
23 23 | )
|
|
||||||
24 |+from airflow.providers.amazon.aws.assets.s3 import convert_asset_to_openlineage
|
|
||||||
24 25 |
|
|
||||||
25 26 | AvpEntities.DATASET
|
|
||||||
26 27 |
|
|
||||||
27 28 | s3_create_dataset()
|
|
||||||
28 |-s3_convert_dataset_to_openlineage()
|
|
||||||
29 |+convert_asset_to_openlineage()
|
|
||||||
29 30 |
|
|
||||||
30 31 | io_create_dataset()
|
|
||||||
31 32 | io_convert_dataset_to_openlineage()
|
|
||||||
|
|
||||||
AIR301_provider_names_fix.py:36:1: AIR301 [*] `airflow.providers.google.datasets.bigquery.create_dataset` is removed in Airflow 3.0
|
|
||||||
|
|
|
||||||
35 | # airflow.providers.google.datasets.bigquery
|
|
||||||
36 | bigquery_create_dataset()
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^ AIR301
|
|
||||||
37 | # airflow.providers.google.datasets.gcs
|
|
||||||
38 | gcs_create_dataset()
|
|
||||||
|
|
|
||||||
= help: Use `airflow.providers.google.assets.bigquery.create_asset` instead
|
|
||||||
|
|
||||||
ℹ Safe fix
|
|
||||||
21 21 | DatasetInfo,
|
|
||||||
22 22 | translate_airflow_dataset,
|
|
||||||
23 23 | )
|
|
||||||
24 |+from airflow.providers.google.assets.bigquery import create_asset
|
|
||||||
24 25 |
|
|
||||||
25 26 | AvpEntities.DATASET
|
|
||||||
26 27 |
|
|
||||||
--------------------------------------------------------------------------------
|
|
||||||
33 34 |
|
|
||||||
34 35 |
|
|
||||||
35 36 | # airflow.providers.google.datasets.bigquery
|
|
||||||
36 |-bigquery_create_dataset()
|
|
||||||
37 |+create_asset()
|
|
||||||
37 38 | # airflow.providers.google.datasets.gcs
|
|
||||||
38 39 | gcs_create_dataset()
|
|
||||||
39 40 | gcs_convert_dataset_to_openlineage()
|
|
||||||
|
|
||||||
AIR301_provider_names_fix.py:38:1: AIR301 [*] `airflow.providers.google.datasets.gcs.create_dataset` is removed in Airflow 3.0
|
|
||||||
|
|
|
||||||
36 | bigquery_create_dataset()
|
|
||||||
37 | # airflow.providers.google.datasets.gcs
|
|
||||||
38 | gcs_create_dataset()
|
|
||||||
| ^^^^^^^^^^^^^^^^^^ AIR301
|
|
||||||
39 | gcs_convert_dataset_to_openlineage()
|
|
||||||
40 | # airflow.providers.openlineage.utils.utils
|
|
||||||
|
|
|
||||||
= help: Use `airflow.providers.google.assets.gcs.create_asset` instead
|
|
||||||
|
|
||||||
ℹ Safe fix
|
|
||||||
21 21 | DatasetInfo,
|
|
||||||
22 22 | translate_airflow_dataset,
|
|
||||||
23 23 | )
|
|
||||||
24 |+from airflow.providers.google.assets.gcs import create_asset
|
|
||||||
24 25 |
|
|
||||||
25 26 | AvpEntities.DATASET
|
|
||||||
26 27 |
|
|
||||||
--------------------------------------------------------------------------------
|
|
||||||
35 36 | # airflow.providers.google.datasets.bigquery
|
|
||||||
36 37 | bigquery_create_dataset()
|
|
||||||
37 38 | # airflow.providers.google.datasets.gcs
|
|
||||||
38 |-gcs_create_dataset()
|
|
||||||
39 |+create_asset()
|
|
||||||
39 40 | gcs_convert_dataset_to_openlineage()
|
|
||||||
40 41 | # airflow.providers.openlineage.utils.utils
|
|
||||||
41 42 | DatasetInfo()
|
|
||||||
|
|
||||||
AIR301_provider_names_fix.py:39:1: AIR301 [*] `airflow.providers.google.datasets.gcs.convert_dataset_to_openlineage` is removed in Airflow 3.0
|
|
||||||
|
|
|
||||||
37 | # airflow.providers.google.datasets.gcs
|
|
||||||
38 | gcs_create_dataset()
|
|
||||||
39 | gcs_convert_dataset_to_openlineage()
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ AIR301
|
|
||||||
40 | # airflow.providers.openlineage.utils.utils
|
|
||||||
41 | DatasetInfo()
|
|
||||||
|
|
|
||||||
= help: Use `airflow.providers.google.assets.gcs.convert_asset_to_openlineage` instead
|
|
||||||
|
|
||||||
ℹ Safe fix
|
|
||||||
21 21 | DatasetInfo,
|
|
||||||
22 22 | translate_airflow_dataset,
|
|
||||||
23 23 | )
|
|
||||||
24 |+from airflow.providers.google.assets.gcs import convert_asset_to_openlineage
|
|
||||||
24 25 |
|
|
||||||
25 26 | AvpEntities.DATASET
|
|
||||||
26 27 |
|
|
||||||
--------------------------------------------------------------------------------
|
|
||||||
36 37 | bigquery_create_dataset()
|
|
||||||
37 38 | # airflow.providers.google.datasets.gcs
|
|
||||||
38 39 | gcs_create_dataset()
|
|
||||||
39 |-gcs_convert_dataset_to_openlineage()
|
|
||||||
40 |+convert_asset_to_openlineage()
|
|
||||||
40 41 | # airflow.providers.openlineage.utils.utils
|
|
||||||
41 42 | DatasetInfo()
|
|
||||||
42 43 | translate_airflow_dataset()
|
|
||||||
|
|
||||||
AIR301_provider_names_fix.py:41:1: AIR301 [*] `airflow.providers.openlineage.utils.utils.DatasetInfo` is removed in Airflow 3.0
|
|
||||||
|
|
|
||||||
39 | gcs_convert_dataset_to_openlineage()
|
|
||||||
40 | # airflow.providers.openlineage.utils.utils
|
|
||||||
41 | DatasetInfo()
|
|
||||||
| ^^^^^^^^^^^ AIR301
|
| ^^^^^^^^^^^ AIR301
|
||||||
42 | translate_airflow_dataset()
|
15 | translate_airflow_dataset()
|
||||||
43 | #
|
|
||||||
|
|
|
|
||||||
= help: Use `airflow.providers.openlineage.utils.utils.AssetInfo` instead
|
= help: Use `AssetInfo` from `airflow.providers.openlineage.utils.utils` instead.
|
||||||
|
|
||||||
ℹ Safe fix
|
ℹ Safe fix
|
||||||
20 20 | from airflow.providers.openlineage.utils.utils import (
|
4 4 | from airflow.providers.openlineage.utils.utils import (
|
||||||
21 21 | DatasetInfo,
|
5 5 | DatasetInfo,
|
||||||
22 22 | translate_airflow_dataset,
|
6 6 | translate_airflow_dataset,
|
||||||
23 |+AssetInfo,
|
7 |+AssetInfo,
|
||||||
23 24 | )
|
7 8 | )
|
||||||
24 25 |
|
8 9 | from airflow.secrets.local_filesystem import load_connections
|
||||||
25 26 | AvpEntities.DATASET
|
9 10 | from airflow.security.permissions import RESOURCE_DATASET
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
38 39 | gcs_create_dataset()
|
11 12 | AvpEntities.DATASET
|
||||||
39 40 | gcs_convert_dataset_to_openlineage()
|
12 13 |
|
||||||
40 41 | # airflow.providers.openlineage.utils.utils
|
13 14 | # airflow.providers.openlineage.utils.utils
|
||||||
41 |-DatasetInfo()
|
14 |-DatasetInfo()
|
||||||
42 |+AssetInfo()
|
15 |+AssetInfo()
|
||||||
42 43 | translate_airflow_dataset()
|
15 16 | translate_airflow_dataset()
|
||||||
43 44 | #
|
16 17 |
|
||||||
44 45 | # airflow.secrets.local_filesystem
|
17 18 | # airflow.secrets.local_filesystem
|
||||||
|
|
||||||
AIR301_provider_names_fix.py:42:1: AIR301 [*] `airflow.providers.openlineage.utils.utils.translate_airflow_dataset` is removed in Airflow 3.0
|
AIR301_provider_names_fix.py:15:1: AIR301 [*] `airflow.providers.openlineage.utils.utils.translate_airflow_dataset` is removed in Airflow 3.0
|
||||||
|
|
|
|
||||||
40 | # airflow.providers.openlineage.utils.utils
|
13 | # airflow.providers.openlineage.utils.utils
|
||||||
41 | DatasetInfo()
|
14 | DatasetInfo()
|
||||||
42 | translate_airflow_dataset()
|
15 | translate_airflow_dataset()
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^ AIR301
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^ AIR301
|
||||||
43 | #
|
16 |
|
||||||
44 | # airflow.secrets.local_filesystem
|
17 | # airflow.secrets.local_filesystem
|
||||||
|
|
|
|
||||||
= help: Use `airflow.providers.openlineage.utils.utils.translate_airflow_asset` instead
|
= help: Use `translate_airflow_asset` from `airflow.providers.openlineage.utils.utils` instead.
|
||||||
|
|
||||||
ℹ Safe fix
|
ℹ Safe fix
|
||||||
20 20 | from airflow.providers.openlineage.utils.utils import (
|
4 4 | from airflow.providers.openlineage.utils.utils import (
|
||||||
21 21 | DatasetInfo,
|
5 5 | DatasetInfo,
|
||||||
22 22 | translate_airflow_dataset,
|
6 6 | translate_airflow_dataset,
|
||||||
23 |+translate_airflow_asset,
|
7 |+translate_airflow_asset,
|
||||||
23 24 | )
|
7 8 | )
|
||||||
24 25 |
|
8 9 | from airflow.secrets.local_filesystem import load_connections
|
||||||
25 26 | AvpEntities.DATASET
|
9 10 | from airflow.security.permissions import RESOURCE_DATASET
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
39 40 | gcs_convert_dataset_to_openlineage()
|
12 13 |
|
||||||
40 41 | # airflow.providers.openlineage.utils.utils
|
13 14 | # airflow.providers.openlineage.utils.utils
|
||||||
41 42 | DatasetInfo()
|
14 15 | DatasetInfo()
|
||||||
42 |-translate_airflow_dataset()
|
15 |-translate_airflow_dataset()
|
||||||
43 |+translate_airflow_asset()
|
16 |+translate_airflow_asset()
|
||||||
43 44 | #
|
16 17 |
|
||||||
44 45 | # airflow.secrets.local_filesystem
|
17 18 | # airflow.secrets.local_filesystem
|
||||||
45 46 | load_connections()
|
18 19 | load_connections()
|
||||||
|
|
||||||
|
AIR301_provider_names_fix.py:18:1: AIR301 [*] `airflow.secrets.local_filesystem.load_connections` is removed in Airflow 3.0
|
||||||
|
|
|
||||||
|
17 | # airflow.secrets.local_filesystem
|
||||||
|
18 | load_connections()
|
||||||
|
| ^^^^^^^^^^^^^^^^ AIR301
|
||||||
|
19 |
|
||||||
|
20 | # airflow.security.permissions
|
||||||
|
|
|
||||||
|
= help: Use `load_connections_dict` from `airflow.secrets.local_filesystem` instead.
|
||||||
|
|
||||||
|
ℹ Safe fix
|
||||||
|
5 5 | DatasetInfo,
|
||||||
|
6 6 | translate_airflow_dataset,
|
||||||
|
7 7 | )
|
||||||
|
8 |-from airflow.secrets.local_filesystem import load_connections
|
||||||
|
8 |+from airflow.secrets.local_filesystem import load_connections, load_connections_dict
|
||||||
|
9 9 | from airflow.security.permissions import RESOURCE_DATASET
|
||||||
|
10 10 |
|
||||||
|
11 11 | AvpEntities.DATASET
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
15 15 | translate_airflow_dataset()
|
||||||
|
16 16 |
|
||||||
|
17 17 | # airflow.secrets.local_filesystem
|
||||||
|
18 |-load_connections()
|
||||||
|
18 |+load_connections_dict()
|
||||||
|
19 19 |
|
||||||
|
20 20 | # airflow.security.permissions
|
||||||
|
21 21 | RESOURCE_DATASET
|
||||||
|
|
||||||
|
AIR301_provider_names_fix.py:21:1: AIR301 [*] `airflow.security.permissions.RESOURCE_DATASET` is removed in Airflow 3.0
|
||||||
|
|
|
||||||
|
20 | # airflow.security.permissions
|
||||||
|
21 | RESOURCE_DATASET
|
||||||
|
| ^^^^^^^^^^^^^^^^ AIR301
|
||||||
|
22 |
|
||||||
|
23 | from airflow.providers.amazon.aws.datasets.s3 import (
|
||||||
|
|
|
||||||
|
= help: Use `RESOURCE_ASSET` from `airflow.security.permissions` instead.
|
||||||
|
|
||||||
|
ℹ Safe fix
|
||||||
|
6 6 | translate_airflow_dataset,
|
||||||
|
7 7 | )
|
||||||
|
8 8 | from airflow.secrets.local_filesystem import load_connections
|
||||||
|
9 |-from airflow.security.permissions import RESOURCE_DATASET
|
||||||
|
9 |+from airflow.security.permissions import RESOURCE_DATASET, RESOURCE_ASSET
|
||||||
|
10 10 |
|
||||||
|
11 11 | AvpEntities.DATASET
|
||||||
|
12 12 |
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
18 18 | load_connections()
|
||||||
|
19 19 |
|
||||||
|
20 20 | # airflow.security.permissions
|
||||||
|
21 |-RESOURCE_DATASET
|
||||||
|
21 |+RESOURCE_ASSET
|
||||||
|
22 22 |
|
||||||
|
23 23 | from airflow.providers.amazon.aws.datasets.s3 import (
|
||||||
|
24 24 | convert_dataset_to_openlineage as s3_convert_dataset_to_openlineage,
|
||||||
|
|
||||||
|
AIR301_provider_names_fix.py:28:1: AIR301 [*] `airflow.providers.amazon.aws.datasets.s3.create_dataset` is removed in Airflow 3.0
|
||||||
|
|
|
||||||
|
26 | from airflow.providers.amazon.aws.datasets.s3 import create_dataset as s3_create_dataset
|
||||||
|
27 |
|
||||||
|
28 | s3_create_dataset()
|
||||||
|
| ^^^^^^^^^^^^^^^^^ AIR301
|
||||||
|
29 | s3_convert_dataset_to_openlineage()
|
||||||
|
|
|
||||||
|
= help: Use `create_asset` from `airflow.providers.amazon.aws.assets.s3` instead.
|
||||||
|
|
||||||
|
ℹ Safe fix
|
||||||
|
24 24 | convert_dataset_to_openlineage as s3_convert_dataset_to_openlineage,
|
||||||
|
25 25 | )
|
||||||
|
26 26 | from airflow.providers.amazon.aws.datasets.s3 import create_dataset as s3_create_dataset
|
||||||
|
27 |+from airflow.providers.amazon.aws.assets.s3 import create_asset
|
||||||
|
27 28 |
|
||||||
|
28 |-s3_create_dataset()
|
||||||
|
29 |+create_asset()
|
||||||
|
29 30 | s3_convert_dataset_to_openlineage()
|
||||||
|
30 31 |
|
||||||
|
31 32 | from airflow.providers.common.io.dataset.file import (
|
||||||
|
|
||||||
|
AIR301_provider_names_fix.py:29:1: AIR301 [*] `airflow.providers.amazon.aws.datasets.s3.convert_dataset_to_openlineage` is removed in Airflow 3.0
|
||||||
|
|
|
||||||
|
28 | s3_create_dataset()
|
||||||
|
29 | s3_convert_dataset_to_openlineage()
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ AIR301
|
||||||
|
30 |
|
||||||
|
31 | from airflow.providers.common.io.dataset.file import (
|
||||||
|
|
|
||||||
|
= help: Use `convert_asset_to_openlineage` from `airflow.providers.amazon.aws.assets.s3` instead.
|
||||||
|
|
||||||
|
ℹ Safe fix
|
||||||
|
24 24 | convert_dataset_to_openlineage as s3_convert_dataset_to_openlineage,
|
||||||
|
25 25 | )
|
||||||
|
26 26 | from airflow.providers.amazon.aws.datasets.s3 import create_dataset as s3_create_dataset
|
||||||
|
27 |+from airflow.providers.amazon.aws.assets.s3 import convert_asset_to_openlineage
|
||||||
|
27 28 |
|
||||||
|
28 29 | s3_create_dataset()
|
||||||
|
29 |-s3_convert_dataset_to_openlineage()
|
||||||
|
30 |+convert_asset_to_openlineage()
|
||||||
|
30 31 |
|
||||||
|
31 32 | from airflow.providers.common.io.dataset.file import (
|
||||||
|
32 33 | convert_dataset_to_openlineage as io_convert_dataset_to_openlineage,
|
||||||
|
|
||||||
|
AIR301_provider_names_fix.py:45:1: AIR301 [*] `airflow.providers.google.datasets.bigquery.create_dataset` is removed in Airflow 3.0
|
||||||
|
|
|
||||||
|
43 | )
|
||||||
|
44 |
|
||||||
|
45 | bigquery_create_dataset()
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^ AIR301
|
||||||
|
46 |
|
||||||
|
47 | # airflow.providers.google.datasets.gcs
|
||||||
|
|
|
||||||
|
= help: Use `create_asset` from `airflow.providers.google.assets.bigquery` instead.
|
||||||
|
|
||||||
|
ℹ Safe fix
|
||||||
|
41 41 | from airflow.providers.google.datasets.bigquery import (
|
||||||
|
42 42 | create_dataset as bigquery_create_dataset,
|
||||||
|
43 43 | )
|
||||||
|
44 |+from airflow.providers.google.assets.bigquery import create_asset
|
||||||
|
44 45 |
|
||||||
|
45 |-bigquery_create_dataset()
|
||||||
|
46 |+create_asset()
|
||||||
|
46 47 |
|
||||||
|
47 48 | # airflow.providers.google.datasets.gcs
|
||||||
|
48 49 | from airflow.providers.google.datasets.gcs import (
|
||||||
|
|
||||||
|
AIR301_provider_names_fix.py:53:1: AIR301 [*] `airflow.providers.google.datasets.gcs.create_dataset` is removed in Airflow 3.0
|
||||||
|
|
|
||||||
|
51 | from airflow.providers.google.datasets.gcs import create_dataset as gcs_create_dataset
|
||||||
|
52 |
|
||||||
|
53 | gcs_create_dataset()
|
||||||
|
| ^^^^^^^^^^^^^^^^^^ AIR301
|
||||||
|
54 | gcs_convert_dataset_to_openlineage()
|
||||||
|
|
|
||||||
|
= help: Use `create_asset` from `airflow.providers.google.assets.gcs` instead.
|
||||||
|
|
||||||
|
ℹ Safe fix
|
||||||
|
49 49 | convert_dataset_to_openlineage as gcs_convert_dataset_to_openlineage,
|
||||||
|
50 50 | )
|
||||||
|
51 51 | from airflow.providers.google.datasets.gcs import create_dataset as gcs_create_dataset
|
||||||
|
52 |+from airflow.providers.google.assets.gcs import create_asset
|
||||||
|
52 53 |
|
||||||
|
53 |-gcs_create_dataset()
|
||||||
|
54 |+create_asset()
|
||||||
|
54 55 | gcs_convert_dataset_to_openlineage()
|
||||||
|
|
||||||
|
AIR301_provider_names_fix.py:54:1: AIR301 [*] `airflow.providers.google.datasets.gcs.convert_dataset_to_openlineage` is removed in Airflow 3.0
|
||||||
|
|
|
||||||
|
53 | gcs_create_dataset()
|
||||||
|
54 | gcs_convert_dataset_to_openlineage()
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ AIR301
|
||||||
|
|
|
||||||
|
= help: Use `convert_asset_to_openlineage` from `airflow.providers.google.assets.gcs` instead.
|
||||||
|
|
||||||
|
ℹ Safe fix
|
||||||
|
49 49 | convert_dataset_to_openlineage as gcs_convert_dataset_to_openlineage,
|
||||||
|
50 50 | )
|
||||||
|
51 51 | from airflow.providers.google.datasets.gcs import create_dataset as gcs_create_dataset
|
||||||
|
52 |+from airflow.providers.google.assets.gcs import convert_asset_to_openlineage
|
||||||
|
52 53 |
|
||||||
|
53 54 | gcs_create_dataset()
|
||||||
|
54 |-gcs_convert_dataset_to_openlineage()
|
||||||
|
55 |+convert_asset_to_openlineage()
|
||||||
|
|||||||
@@ -1,113 +1,252 @@
|
|||||||
---
|
---
|
||||||
source: crates/ruff_linter/src/rules/airflow/mod.rs
|
source: crates/ruff_linter/src/rules/airflow/mod.rs
|
||||||
---
|
---
|
||||||
AIR302_amazon.py:23:1: AIR302 `airflow.hooks.S3_hook.S3Hook` is moved into `amazon` provider in Airflow 3.0;
|
AIR302_amazon.py:14:1: AIR302 [*] `airflow.hooks.S3_hook.S3Hook` is moved into `amazon` provider in Airflow 3.0;
|
||||||
|
|
|
|
||||||
21 | from airflow.sensors.s3_key_sensor import S3KeySensor
|
12 | from airflow.sensors.s3_key_sensor import S3KeySensor
|
||||||
22 |
|
13 |
|
||||||
23 | S3Hook()
|
14 | S3Hook()
|
||||||
| ^^^^^^ AIR302
|
| ^^^^^^ AIR302
|
||||||
24 | provide_bucket_name()
|
15 | provide_bucket_name()
|
||||||
|
|
|
|
||||||
= help: Install `apache-airflow-providers-amazon>=1.0.0` and use `airflow.providers.amazon.aws.hooks.s3.S3Hook` instead.
|
= help: Install `apache-airflow-providers-amazon>=1.0.0` and use `S3Hook` from `airflow.providers.amazon.aws.hooks.s3` instead.
|
||||||
|
|
||||||
AIR302_amazon.py:24:1: AIR302 `airflow.hooks.S3_hook.provide_bucket_name` is moved into `amazon` provider in Airflow 3.0;
|
ℹ Unsafe fix
|
||||||
|
1 1 | from __future__ import annotations
|
||||||
|
2 2 |
|
||||||
|
3 3 | from airflow.hooks.S3_hook import (
|
||||||
|
4 |- S3Hook,
|
||||||
|
5 4 | provide_bucket_name,
|
||||||
|
6 5 | )
|
||||||
|
7 6 | from airflow.operators.gcs_to_s3 import GCSToS3Operator
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
10 9 | from airflow.operators.s3_file_transform_operator import S3FileTransformOperator
|
||||||
|
11 10 | from airflow.operators.s3_to_redshift_operator import S3ToRedshiftOperator
|
||||||
|
12 11 | from airflow.sensors.s3_key_sensor import S3KeySensor
|
||||||
|
12 |+from airflow.providers.amazon.aws.hooks.s3 import S3Hook
|
||||||
|
13 13 |
|
||||||
|
14 14 | S3Hook()
|
||||||
|
15 15 | provide_bucket_name()
|
||||||
|
|
||||||
|
AIR302_amazon.py:15:1: AIR302 [*] `airflow.hooks.S3_hook.provide_bucket_name` is moved into `amazon` provider in Airflow 3.0;
|
||||||
|
|
|
|
||||||
23 | S3Hook()
|
14 | S3Hook()
|
||||||
24 | provide_bucket_name()
|
15 | provide_bucket_name()
|
||||||
| ^^^^^^^^^^^^^^^^^^^ AIR302
|
| ^^^^^^^^^^^^^^^^^^^ AIR302
|
||||||
25 |
|
16 |
|
||||||
26 | GCSToS3Operator()
|
17 | GCSToS3Operator()
|
||||||
|
|
|
|
||||||
= help: Install `apache-airflow-providers-amazon>=1.0.0` and use `airflow.providers.amazon.aws.hooks.s3.provide_bucket_name` instead.
|
= help: Install `apache-airflow-providers-amazon>=1.0.0` and use `provide_bucket_name` from `airflow.providers.amazon.aws.hooks.s3` instead.
|
||||||
|
|
||||||
AIR302_amazon.py:26:1: AIR302 `airflow.operators.gcs_to_s3.GCSToS3Operator` is moved into `amazon` provider in Airflow 3.0;
|
ℹ Unsafe fix
|
||||||
|
2 2 |
|
||||||
|
3 3 | from airflow.hooks.S3_hook import (
|
||||||
|
4 4 | S3Hook,
|
||||||
|
5 |- provide_bucket_name,
|
||||||
|
6 5 | )
|
||||||
|
7 6 | from airflow.operators.gcs_to_s3 import GCSToS3Operator
|
||||||
|
8 7 | from airflow.operators.google_api_to_s3_transfer import GoogleApiToS3Operator
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
10 9 | from airflow.operators.s3_file_transform_operator import S3FileTransformOperator
|
||||||
|
11 10 | from airflow.operators.s3_to_redshift_operator import S3ToRedshiftOperator
|
||||||
|
12 11 | from airflow.sensors.s3_key_sensor import S3KeySensor
|
||||||
|
12 |+from airflow.providers.amazon.aws.hooks.s3 import provide_bucket_name
|
||||||
|
13 13 |
|
||||||
|
14 14 | S3Hook()
|
||||||
|
15 15 | provide_bucket_name()
|
||||||
|
|
||||||
|
AIR302_amazon.py:17:1: AIR302 [*] `airflow.operators.gcs_to_s3.GCSToS3Operator` is moved into `amazon` provider in Airflow 3.0;
|
||||||
|
|
|
|
||||||
24 | provide_bucket_name()
|
15 | provide_bucket_name()
|
||||||
25 |
|
16 |
|
||||||
26 | GCSToS3Operator()
|
17 | GCSToS3Operator()
|
||||||
| ^^^^^^^^^^^^^^^ AIR302
|
| ^^^^^^^^^^^^^^^ AIR302
|
||||||
27 |
|
18 | GoogleApiToS3Operator()
|
||||||
28 | GoogleApiToS3Operator()
|
19 | RedshiftToS3Operator()
|
||||||
|
|
|
|
||||||
= help: Install `apache-airflow-providers-amazon>=1.0.0` and use `airflow.providers.amazon.aws.transfers.gcs_to_s3.GCSToS3Operator` instead.
|
= help: Install `apache-airflow-providers-amazon>=1.0.0` and use `GCSToS3Operator` from `airflow.providers.amazon.aws.transfers.gcs_to_s3` instead.
|
||||||
|
|
||||||
AIR302_amazon.py:28:1: AIR302 `airflow.operators.google_api_to_s3_transfer.GoogleApiToS3Operator` is moved into `amazon` provider in Airflow 3.0;
|
ℹ Unsafe fix
|
||||||
|
4 4 | S3Hook,
|
||||||
|
5 5 | provide_bucket_name,
|
||||||
|
6 6 | )
|
||||||
|
7 |-from airflow.operators.gcs_to_s3 import GCSToS3Operator
|
||||||
|
8 7 | from airflow.operators.google_api_to_s3_transfer import GoogleApiToS3Operator
|
||||||
|
9 8 | from airflow.operators.redshift_to_s3_operator import RedshiftToS3Operator
|
||||||
|
10 9 | from airflow.operators.s3_file_transform_operator import S3FileTransformOperator
|
||||||
|
11 10 | from airflow.operators.s3_to_redshift_operator import S3ToRedshiftOperator
|
||||||
|
12 11 | from airflow.sensors.s3_key_sensor import S3KeySensor
|
||||||
|
12 |+from airflow.providers.amazon.aws.transfers.gcs_to_s3 import GCSToS3Operator
|
||||||
|
13 13 |
|
||||||
|
14 14 | S3Hook()
|
||||||
|
15 15 | provide_bucket_name()
|
||||||
|
|
||||||
|
AIR302_amazon.py:18:1: AIR302 [*] `airflow.operators.google_api_to_s3_transfer.GoogleApiToS3Operator` is moved into `amazon` provider in Airflow 3.0;
|
||||||
|
|
|
|
||||||
26 | GCSToS3Operator()
|
17 | GCSToS3Operator()
|
||||||
27 |
|
18 | GoogleApiToS3Operator()
|
||||||
28 | GoogleApiToS3Operator()
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^ AIR302
|
| ^^^^^^^^^^^^^^^^^^^^^ AIR302
|
||||||
29 | GoogleApiToS3Transfer()
|
19 | RedshiftToS3Operator()
|
||||||
|
20 | S3FileTransformOperator()
|
||||||
|
|
|
|
||||||
= help: Install `apache-airflow-providers-amazon>=1.0.0` and use `airflow.providers.amazon.aws.transfers.google_api_to_s3.GoogleApiToS3Operator` instead.
|
= help: Install `apache-airflow-providers-amazon>=1.0.0` and use `GoogleApiToS3Operator` from `airflow.providers.amazon.aws.transfers.google_api_to_s3` instead.
|
||||||
|
|
||||||
AIR302_amazon.py:29:1: AIR302 `airflow.operators.google_api_to_s3_transfer.GoogleApiToS3Transfer` is moved into `amazon` provider in Airflow 3.0;
|
ℹ Unsafe fix
|
||||||
|
|
5 5 | provide_bucket_name,
|
||||||
28 | GoogleApiToS3Operator()
|
6 6 | )
|
||||||
29 | GoogleApiToS3Transfer()
|
7 7 | from airflow.operators.gcs_to_s3 import GCSToS3Operator
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^ AIR302
|
8 |-from airflow.operators.google_api_to_s3_transfer import GoogleApiToS3Operator
|
||||||
30 |
|
9 8 | from airflow.operators.redshift_to_s3_operator import RedshiftToS3Operator
|
||||||
31 | RedshiftToS3Operator()
|
10 9 | from airflow.operators.s3_file_transform_operator import S3FileTransformOperator
|
||||||
|
|
11 10 | from airflow.operators.s3_to_redshift_operator import S3ToRedshiftOperator
|
||||||
= help: Install `apache-airflow-providers-amazon>=1.0.0` and use `airflow.providers.amazon.aws.transfers.google_api_to_s3.GoogleApiToS3Operator` instead.
|
12 11 | from airflow.sensors.s3_key_sensor import S3KeySensor
|
||||||
|
12 |+from airflow.providers.amazon.aws.transfers.google_api_to_s3 import GoogleApiToS3Operator
|
||||||
|
13 13 |
|
||||||
|
14 14 | S3Hook()
|
||||||
|
15 15 | provide_bucket_name()
|
||||||
|
|
||||||
AIR302_amazon.py:31:1: AIR302 `airflow.operators.redshift_to_s3_operator.RedshiftToS3Operator` is moved into `amazon` provider in Airflow 3.0;
|
AIR302_amazon.py:19:1: AIR302 [*] `airflow.operators.redshift_to_s3_operator.RedshiftToS3Operator` is moved into `amazon` provider in Airflow 3.0;
|
||||||
|
|
|
|
||||||
29 | GoogleApiToS3Transfer()
|
17 | GCSToS3Operator()
|
||||||
30 |
|
18 | GoogleApiToS3Operator()
|
||||||
31 | RedshiftToS3Operator()
|
19 | RedshiftToS3Operator()
|
||||||
| ^^^^^^^^^^^^^^^^^^^^ AIR302
|
| ^^^^^^^^^^^^^^^^^^^^ AIR302
|
||||||
32 | RedshiftToS3Transfer()
|
20 | S3FileTransformOperator()
|
||||||
|
21 | S3ToRedshiftOperator()
|
||||||
|
|
|
|
||||||
= help: Install `apache-airflow-providers-amazon>=1.0.0` and use `airflow.providers.amazon.aws.transfers.redshift_to_s3.RedshiftToS3Operator` instead.
|
= help: Install `apache-airflow-providers-amazon>=1.0.0` and use `RedshiftToS3Operator` from `airflow.providers.amazon.aws.transfers.redshift_to_s3` instead.
|
||||||
|
|
||||||
AIR302_amazon.py:32:1: AIR302 `airflow.operators.redshift_to_s3_operator.RedshiftToS3Transfer` is moved into `amazon` provider in Airflow 3.0;
|
ℹ Unsafe fix
|
||||||
|
|
6 6 | )
|
||||||
31 | RedshiftToS3Operator()
|
7 7 | from airflow.operators.gcs_to_s3 import GCSToS3Operator
|
||||||
32 | RedshiftToS3Transfer()
|
8 8 | from airflow.operators.google_api_to_s3_transfer import GoogleApiToS3Operator
|
||||||
| ^^^^^^^^^^^^^^^^^^^^ AIR302
|
9 |-from airflow.operators.redshift_to_s3_operator import RedshiftToS3Operator
|
||||||
33 |
|
10 9 | from airflow.operators.s3_file_transform_operator import S3FileTransformOperator
|
||||||
34 | S3FileTransformOperator()
|
11 10 | from airflow.operators.s3_to_redshift_operator import S3ToRedshiftOperator
|
||||||
|
|
12 11 | from airflow.sensors.s3_key_sensor import S3KeySensor
|
||||||
= help: Install `apache-airflow-providers-amazon>=1.0.0` and use `airflow.providers.amazon.aws.transfers.redshift_to_s3.RedshiftToS3Operator` instead.
|
12 |+from airflow.providers.amazon.aws.transfers.redshift_to_s3 import RedshiftToS3Operator
|
||||||
|
13 13 |
|
||||||
|
14 14 | S3Hook()
|
||||||
|
15 15 | provide_bucket_name()
|
||||||
|
|
||||||
AIR302_amazon.py:34:1: AIR302 `airflow.operators.s3_file_transform_operator.S3FileTransformOperator` is moved into `amazon` provider in Airflow 3.0;
|
AIR302_amazon.py:20:1: AIR302 [*] `airflow.operators.s3_file_transform_operator.S3FileTransformOperator` is moved into `amazon` provider in Airflow 3.0;
|
||||||
|
|
|
|
||||||
32 | RedshiftToS3Transfer()
|
18 | GoogleApiToS3Operator()
|
||||||
33 |
|
19 | RedshiftToS3Operator()
|
||||||
34 | S3FileTransformOperator()
|
20 | S3FileTransformOperator()
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^ AIR302
|
| ^^^^^^^^^^^^^^^^^^^^^^^ AIR302
|
||||||
35 |
|
21 | S3ToRedshiftOperator()
|
||||||
36 | S3ToRedshiftOperator()
|
22 | S3KeySensor()
|
||||||
|
|
|
|
||||||
= help: Install `apache-airflow-providers-amazon>=3.0.0` and use `airflow.providers.amazon.aws.operators.s3.S3FileTransformOperator` instead.
|
= help: Install `apache-airflow-providers-amazon>=3.0.0` and use `S3FileTransformOperator` from `airflow.providers.amazon.aws.operators.s3` instead.
|
||||||
|
|
||||||
AIR302_amazon.py:36:1: AIR302 `airflow.operators.s3_to_redshift_operator.S3ToRedshiftOperator` is moved into `amazon` provider in Airflow 3.0;
|
ℹ Unsafe fix
|
||||||
|
7 7 | from airflow.operators.gcs_to_s3 import GCSToS3Operator
|
||||||
|
8 8 | from airflow.operators.google_api_to_s3_transfer import GoogleApiToS3Operator
|
||||||
|
9 9 | from airflow.operators.redshift_to_s3_operator import RedshiftToS3Operator
|
||||||
|
10 |-from airflow.operators.s3_file_transform_operator import S3FileTransformOperator
|
||||||
|
11 10 | from airflow.operators.s3_to_redshift_operator import S3ToRedshiftOperator
|
||||||
|
12 11 | from airflow.sensors.s3_key_sensor import S3KeySensor
|
||||||
|
12 |+from airflow.providers.amazon.aws.operators.s3 import S3FileTransformOperator
|
||||||
|
13 13 |
|
||||||
|
14 14 | S3Hook()
|
||||||
|
15 15 | provide_bucket_name()
|
||||||
|
|
||||||
|
AIR302_amazon.py:21:1: AIR302 [*] `airflow.operators.s3_to_redshift_operator.S3ToRedshiftOperator` is moved into `amazon` provider in Airflow 3.0;
|
||||||
|
|
|
|
||||||
34 | S3FileTransformOperator()
|
19 | RedshiftToS3Operator()
|
||||||
35 |
|
20 | S3FileTransformOperator()
|
||||||
36 | S3ToRedshiftOperator()
|
21 | S3ToRedshiftOperator()
|
||||||
| ^^^^^^^^^^^^^^^^^^^^ AIR302
|
| ^^^^^^^^^^^^^^^^^^^^ AIR302
|
||||||
37 | S3ToRedshiftTransfer()
|
22 | S3KeySensor()
|
||||||
|
|
|
|
||||||
= help: Install `apache-airflow-providers-amazon>=1.0.0` and use `airflow.providers.amazon.aws.transfers.s3_to_redshift.S3ToRedshiftOperator` instead.
|
= help: Install `apache-airflow-providers-amazon>=1.0.0` and use `S3ToRedshiftOperator` from `airflow.providers.amazon.aws.transfers.s3_to_redshift` instead.
|
||||||
|
|
||||||
AIR302_amazon.py:37:1: AIR302 `airflow.operators.s3_to_redshift_operator.S3ToRedshiftTransfer` is moved into `amazon` provider in Airflow 3.0;
|
ℹ Unsafe fix
|
||||||
|
|
8 8 | from airflow.operators.google_api_to_s3_transfer import GoogleApiToS3Operator
|
||||||
36 | S3ToRedshiftOperator()
|
9 9 | from airflow.operators.redshift_to_s3_operator import RedshiftToS3Operator
|
||||||
37 | S3ToRedshiftTransfer()
|
10 10 | from airflow.operators.s3_file_transform_operator import S3FileTransformOperator
|
||||||
| ^^^^^^^^^^^^^^^^^^^^ AIR302
|
11 |-from airflow.operators.s3_to_redshift_operator import S3ToRedshiftOperator
|
||||||
38 |
|
12 11 | from airflow.sensors.s3_key_sensor import S3KeySensor
|
||||||
39 | S3KeySensor()
|
12 |+from airflow.providers.amazon.aws.transfers.s3_to_redshift import S3ToRedshiftOperator
|
||||||
|
|
13 13 |
|
||||||
= help: Install `apache-airflow-providers-amazon>=1.0.0` and use `airflow.providers.amazon.aws.transfers.s3_to_redshift.S3ToRedshiftOperator` instead.
|
14 14 | S3Hook()
|
||||||
|
15 15 | provide_bucket_name()
|
||||||
|
|
||||||
AIR302_amazon.py:39:1: AIR302 `airflow.sensors.s3_key_sensor.S3KeySensor` is moved into `amazon` provider in Airflow 3.0;
|
AIR302_amazon.py:22:1: AIR302 [*] `airflow.sensors.s3_key_sensor.S3KeySensor` is moved into `amazon` provider in Airflow 3.0;
|
||||||
|
|
|
|
||||||
37 | S3ToRedshiftTransfer()
|
20 | S3FileTransformOperator()
|
||||||
38 |
|
21 | S3ToRedshiftOperator()
|
||||||
39 | S3KeySensor()
|
22 | S3KeySensor()
|
||||||
| ^^^^^^^^^^^ AIR302
|
| ^^^^^^^^^^^ AIR302
|
||||||
|
23 |
|
||||||
|
24 | from airflow.operators.google_api_to_s3_transfer import GoogleApiToS3Transfer
|
||||||
|
|
|
|
||||||
= help: Install `apache-airflow-providers-amazon>=1.0.0` and use `airflow.providers.amazon.aws.sensors.s3.S3KeySensor` instead.
|
= help: Install `apache-airflow-providers-amazon>=1.0.0` and use `S3KeySensor` from `airflow.providers.amazon.aws.sensors.s3` instead.
|
||||||
|
|
||||||
|
ℹ Unsafe fix
|
||||||
|
9 9 | from airflow.operators.redshift_to_s3_operator import RedshiftToS3Operator
|
||||||
|
10 10 | from airflow.operators.s3_file_transform_operator import S3FileTransformOperator
|
||||||
|
11 11 | from airflow.operators.s3_to_redshift_operator import S3ToRedshiftOperator
|
||||||
|
12 |-from airflow.sensors.s3_key_sensor import S3KeySensor
|
||||||
|
12 |+from airflow.providers.amazon.aws.sensors.s3 import S3KeySensor
|
||||||
|
13 13 |
|
||||||
|
14 14 | S3Hook()
|
||||||
|
15 15 | provide_bucket_name()
|
||||||
|
|
||||||
|
AIR302_amazon.py:26:1: AIR302 [*] `airflow.operators.google_api_to_s3_transfer.GoogleApiToS3Transfer` is moved into `amazon` provider in Airflow 3.0;
|
||||||
|
|
|
||||||
|
24 | from airflow.operators.google_api_to_s3_transfer import GoogleApiToS3Transfer
|
||||||
|
25 |
|
||||||
|
26 | GoogleApiToS3Transfer()
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^ AIR302
|
||||||
|
27 |
|
||||||
|
28 | from airflow.operators.redshift_to_s3_operator import RedshiftToS3Transfer
|
||||||
|
|
|
||||||
|
= help: Install `apache-airflow-providers-amazon>=1.0.0` and use `GoogleApiToS3Operator` from `airflow.providers.amazon.aws.transfers.google_api_to_s3` instead.
|
||||||
|
|
||||||
|
ℹ Unsafe fix
|
||||||
|
22 22 | S3KeySensor()
|
||||||
|
23 23 |
|
||||||
|
24 24 | from airflow.operators.google_api_to_s3_transfer import GoogleApiToS3Transfer
|
||||||
|
25 |+from airflow.providers.amazon.aws.transfers.google_api_to_s3 import GoogleApiToS3Operator
|
||||||
|
25 26 |
|
||||||
|
26 27 | GoogleApiToS3Transfer()
|
||||||
|
27 28 |
|
||||||
|
|
||||||
|
AIR302_amazon.py:30:1: AIR302 [*] `airflow.operators.redshift_to_s3_operator.RedshiftToS3Transfer` is moved into `amazon` provider in Airflow 3.0;
|
||||||
|
|
|
||||||
|
28 | from airflow.operators.redshift_to_s3_operator import RedshiftToS3Transfer
|
||||||
|
29 |
|
||||||
|
30 | RedshiftToS3Transfer()
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^ AIR302
|
||||||
|
31 |
|
||||||
|
32 | from airflow.operators.s3_to_redshift_operator import S3ToRedshiftTransfer
|
||||||
|
|
|
||||||
|
= help: Install `apache-airflow-providers-amazon>=1.0.0` and use `RedshiftToS3Operator` from `airflow.providers.amazon.aws.transfers.redshift_to_s3` instead.
|
||||||
|
|
||||||
|
ℹ Unsafe fix
|
||||||
|
26 26 | GoogleApiToS3Transfer()
|
||||||
|
27 27 |
|
||||||
|
28 28 | from airflow.operators.redshift_to_s3_operator import RedshiftToS3Transfer
|
||||||
|
29 |+from airflow.providers.amazon.aws.transfers.redshift_to_s3 import RedshiftToS3Operator
|
||||||
|
29 30 |
|
||||||
|
30 31 | RedshiftToS3Transfer()
|
||||||
|
31 32 |
|
||||||
|
|
||||||
|
AIR302_amazon.py:34:1: AIR302 [*] `airflow.operators.s3_to_redshift_operator.S3ToRedshiftTransfer` is moved into `amazon` provider in Airflow 3.0;
|
||||||
|
|
|
||||||
|
32 | from airflow.operators.s3_to_redshift_operator import S3ToRedshiftTransfer
|
||||||
|
33 |
|
||||||
|
34 | S3ToRedshiftTransfer()
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^ AIR302
|
||||||
|
|
|
||||||
|
= help: Install `apache-airflow-providers-amazon>=1.0.0` and use `S3ToRedshiftOperator` from `airflow.providers.amazon.aws.transfers.s3_to_redshift` instead.
|
||||||
|
|
||||||
|
ℹ Unsafe fix
|
||||||
|
30 30 | RedshiftToS3Transfer()
|
||||||
|
31 31 |
|
||||||
|
32 32 | from airflow.operators.s3_to_redshift_operator import S3ToRedshiftTransfer
|
||||||
|
33 |+from airflow.providers.amazon.aws.transfers.s3_to_redshift import S3ToRedshiftOperator
|
||||||
|
33 34 |
|
||||||
|
34 35 | S3ToRedshiftTransfer()
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user