Compare commits
1 Commits
alex/union
...
alex/relat
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
288ade8381 |
10
.github/CODEOWNERS
vendored
10
.github/CODEOWNERS
vendored
@@ -20,11 +20,9 @@
|
||||
# ty
|
||||
/crates/ty* @carljm @MichaReiser @AlexWaygood @sharkdp @dcreager
|
||||
/crates/ruff_db/ @carljm @MichaReiser @sharkdp @dcreager
|
||||
/crates/ty_project/ @carljm @MichaReiser @sharkdp @dcreager @Gankra
|
||||
/crates/ty_ide/ @carljm @MichaReiser @AlexWaygood @sharkdp @dcreager @Gankra
|
||||
/crates/ty_server/ @carljm @MichaReiser @sharkdp @dcreager @Gankra
|
||||
/crates/ty_project/ @carljm @MichaReiser @sharkdp @dcreager
|
||||
/crates/ty_server/ @carljm @MichaReiser @sharkdp @dcreager
|
||||
/crates/ty/ @carljm @MichaReiser @sharkdp @dcreager
|
||||
/crates/ty_wasm/ @carljm @MichaReiser @sharkdp @dcreager @Gankra
|
||||
/crates/ty_wasm/ @carljm @MichaReiser @sharkdp @dcreager
|
||||
/scripts/ty_benchmark/ @carljm @MichaReiser @AlexWaygood @sharkdp @dcreager
|
||||
/crates/ty_python_semantic/ @carljm @AlexWaygood @sharkdp @dcreager
|
||||
/crates/ty_module_resolver/ @carljm @MichaReiser @AlexWaygood @Gankra
|
||||
/crates/ty_python_semantic @carljm @AlexWaygood @sharkdp @dcreager
|
||||
|
||||
1
.github/mypy-primer-ty.toml
vendored
1
.github/mypy-primer-ty.toml
vendored
@@ -5,4 +5,5 @@
|
||||
[rules]
|
||||
possibly-unresolved-reference = "warn"
|
||||
possibly-missing-import = "warn"
|
||||
unused-ignore-comment = "warn"
|
||||
division-by-zero = "warn"
|
||||
|
||||
8
.github/workflows/build-binaries.yml
vendored
8
.github/workflows/build-binaries.yml
vendored
@@ -51,7 +51,6 @@ jobs:
|
||||
- name: "Build sdist"
|
||||
uses: PyO3/maturin-action@86b9d133d34bc1b40018696f782949dac11bd380 # v1.49.4
|
||||
with:
|
||||
maturin-version: v1.9.6
|
||||
command: sdist
|
||||
args: --out dist
|
||||
- name: "Test sdist"
|
||||
@@ -82,7 +81,6 @@ jobs:
|
||||
- name: "Build wheels - x86_64"
|
||||
uses: PyO3/maturin-action@86b9d133d34bc1b40018696f782949dac11bd380 # v1.49.4
|
||||
with:
|
||||
maturin-version: v1.9.6
|
||||
target: x86_64
|
||||
args: --release --locked --out dist
|
||||
- name: "Upload wheels"
|
||||
@@ -125,7 +123,6 @@ jobs:
|
||||
- name: "Build wheels - aarch64"
|
||||
uses: PyO3/maturin-action@86b9d133d34bc1b40018696f782949dac11bd380 # v1.49.4
|
||||
with:
|
||||
maturin-version: v1.9.6
|
||||
target: aarch64
|
||||
args: --release --locked --out dist
|
||||
- name: "Test wheel - aarch64"
|
||||
@@ -182,7 +179,6 @@ jobs:
|
||||
- name: "Build wheels"
|
||||
uses: PyO3/maturin-action@86b9d133d34bc1b40018696f782949dac11bd380 # v1.49.4
|
||||
with:
|
||||
maturin-version: v1.9.6
|
||||
target: ${{ matrix.platform.target }}
|
||||
args: --release --locked --out dist
|
||||
env:
|
||||
@@ -236,7 +232,6 @@ jobs:
|
||||
- name: "Build wheels"
|
||||
uses: PyO3/maturin-action@86b9d133d34bc1b40018696f782949dac11bd380 # v1.49.4
|
||||
with:
|
||||
maturin-version: v1.9.6
|
||||
target: ${{ matrix.target }}
|
||||
manylinux: auto
|
||||
args: --release --locked --out dist
|
||||
@@ -313,7 +308,6 @@ jobs:
|
||||
- name: "Build wheels"
|
||||
uses: PyO3/maturin-action@86b9d133d34bc1b40018696f782949dac11bd380 # v1.49.4
|
||||
with:
|
||||
maturin-version: v1.9.6
|
||||
target: ${{ matrix.platform.target }}
|
||||
manylinux: auto
|
||||
docker-options: ${{ matrix.platform.maturin_docker_options }}
|
||||
@@ -380,7 +374,6 @@ jobs:
|
||||
- name: "Build wheels"
|
||||
uses: PyO3/maturin-action@86b9d133d34bc1b40018696f782949dac11bd380 # v1.49.4
|
||||
with:
|
||||
maturin-version: v1.9.6
|
||||
target: ${{ matrix.target }}
|
||||
manylinux: musllinux_1_2
|
||||
args: --release --locked --out dist
|
||||
@@ -446,7 +439,6 @@ jobs:
|
||||
- name: "Build wheels"
|
||||
uses: PyO3/maturin-action@86b9d133d34bc1b40018696f782949dac11bd380 # v1.49.4
|
||||
with:
|
||||
maturin-version: v1.9.6
|
||||
target: ${{ matrix.platform.target }}
|
||||
manylinux: musllinux_1_2
|
||||
args: --release --locked --out dist
|
||||
|
||||
58
.github/workflows/build-wasm.yml
vendored
58
.github/workflows/build-wasm.yml
vendored
@@ -1,58 +0,0 @@
|
||||
# Build ruff_wasm for npm.
|
||||
#
|
||||
# Assumed to run as a subworkflow of .github/workflows/release.yml; specifically, as a local
|
||||
# artifacts job within `cargo-dist`.
|
||||
name: "Build wasm"
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
plan:
|
||||
required: true
|
||||
type: string
|
||||
pull_request:
|
||||
paths:
|
||||
- .github/workflows/build-wasm.yml
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
permissions: {}
|
||||
|
||||
env:
|
||||
CARGO_INCREMENTAL: 0
|
||||
CARGO_NET_RETRY: 10
|
||||
CARGO_TERM_COLOR: always
|
||||
RUSTUP_MAX_RETRIES: 10
|
||||
|
||||
jobs:
|
||||
build:
|
||||
if: ${{ !contains(github.event.pull_request.labels.*.name, 'no-build') }}
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
target: [web, bundler, nodejs]
|
||||
fail-fast: false
|
||||
steps:
|
||||
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: "Install Rust toolchain"
|
||||
run: rustup target add wasm32-unknown-unknown
|
||||
- uses: jetli/wasm-pack-action@0d096b08b4e5a7de8c28de67e11e945404e9eefa # v0.4.0
|
||||
with:
|
||||
version: v0.13.1
|
||||
- uses: jetli/wasm-bindgen-action@20b33e20595891ab1a0ed73145d8a21fc96e7c29 # v0.2.0
|
||||
- name: "Run wasm-pack build"
|
||||
run: wasm-pack build --target ${{ matrix.target }} crates/ruff_wasm
|
||||
- name: "Rename generated package"
|
||||
run: | # Replace the package name w/ jq
|
||||
jq '.name="@astral-sh/ruff-wasm-${{ matrix.target }}"' crates/ruff_wasm/pkg/package.json > /tmp/package.json
|
||||
mv /tmp/package.json crates/ruff_wasm/pkg
|
||||
- run: cp LICENSE crates/ruff_wasm/pkg # wasm-pack does not put the LICENSE file in the pkg
|
||||
- name: "Upload wasm artifact"
|
||||
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
|
||||
with:
|
||||
name: artifacts-wasm-${{ matrix.target }}
|
||||
path: crates/ruff_wasm/pkg
|
||||
35
.github/workflows/publish-wasm.yml
vendored
35
.github/workflows/publish-wasm.yml
vendored
@@ -1,18 +1,25 @@
|
||||
# Publish ruff_wasm to npm.
|
||||
# Build and publish ruff-api for wasm.
|
||||
#
|
||||
# Assumed to run as a subworkflow of .github/workflows/release.yml; specifically, as a publish
|
||||
# job within `cargo-dist`.
|
||||
name: "Publish wasm"
|
||||
name: "Build and publish wasm"
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
workflow_call:
|
||||
inputs:
|
||||
plan:
|
||||
required: true
|
||||
type: string
|
||||
|
||||
env:
|
||||
CARGO_INCREMENTAL: 0
|
||||
CARGO_NET_RETRY: 10
|
||||
CARGO_TERM_COLOR: always
|
||||
RUSTUP_MAX_RETRIES: 10
|
||||
|
||||
jobs:
|
||||
publish:
|
||||
ruff_wasm:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
@@ -22,19 +29,31 @@ jobs:
|
||||
target: [web, bundler, nodejs]
|
||||
fail-fast: false
|
||||
steps:
|
||||
- uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0
|
||||
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
|
||||
with:
|
||||
name: artifacts-wasm-${{ matrix.target }}
|
||||
path: pkg
|
||||
persist-credentials: false
|
||||
- name: "Install Rust toolchain"
|
||||
run: rustup target add wasm32-unknown-unknown
|
||||
- uses: jetli/wasm-pack-action@0d096b08b4e5a7de8c28de67e11e945404e9eefa # v0.4.0
|
||||
with:
|
||||
version: v0.13.1
|
||||
- uses: jetli/wasm-bindgen-action@20b33e20595891ab1a0ed73145d8a21fc96e7c29 # v0.2.0
|
||||
- name: "Run wasm-pack build"
|
||||
run: wasm-pack build --target ${{ matrix.target }} crates/ruff_wasm
|
||||
- name: "Rename generated package"
|
||||
run: | # Replace the package name w/ jq
|
||||
jq '.name="@astral-sh/ruff-wasm-${{ matrix.target }}"' crates/ruff_wasm/pkg/package.json > /tmp/package.json
|
||||
mv /tmp/package.json crates/ruff_wasm/pkg
|
||||
- run: cp LICENSE crates/ruff_wasm/pkg # wasm-pack does not put the LICENSE file in the pkg
|
||||
- uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0
|
||||
with:
|
||||
node-version: 24
|
||||
registry-url: "https://registry.npmjs.org"
|
||||
- name: "Publish (dry-run)"
|
||||
if: ${{ inputs.plan == '' || fromJson(inputs.plan).announcement_tag_is_implicit }}
|
||||
run: npm publish --dry-run pkg
|
||||
run: npm publish --dry-run crates/ruff_wasm/pkg
|
||||
- name: "Publish"
|
||||
if: ${{ inputs.plan != '' && !fromJson(inputs.plan).announcement_tag_is_implicit }}
|
||||
run: npm publish --provenance --access public pkg
|
||||
run: npm publish --provenance --access public crates/ruff_wasm/pkg
|
||||
env:
|
||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
|
||||
13
.github/workflows/release.yml
vendored
13
.github/workflows/release.yml
vendored
@@ -112,22 +112,12 @@ jobs:
|
||||
"contents": "read"
|
||||
"packages": "write"
|
||||
|
||||
custom-build-wasm:
|
||||
needs:
|
||||
- plan
|
||||
if: ${{ needs.plan.outputs.publishing == 'true' || fromJson(needs.plan.outputs.val).ci.github.pr_run_mode == 'upload' || inputs.tag == 'dry-run' }}
|
||||
uses: ./.github/workflows/build-wasm.yml
|
||||
with:
|
||||
plan: ${{ needs.plan.outputs.val }}
|
||||
secrets: inherit
|
||||
|
||||
# Build and package all the platform-agnostic(ish) things
|
||||
build-global-artifacts:
|
||||
needs:
|
||||
- plan
|
||||
- custom-build-binaries
|
||||
- custom-build-docker
|
||||
- custom-build-wasm
|
||||
runs-on: "depot-ubuntu-latest-4"
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
@@ -175,10 +165,9 @@ jobs:
|
||||
- plan
|
||||
- custom-build-binaries
|
||||
- custom-build-docker
|
||||
- custom-build-wasm
|
||||
- build-global-artifacts
|
||||
# Only run if we're "publishing", and only if plan, local and global didn't fail (skipped is fine)
|
||||
if: ${{ always() && needs.plan.result == 'success' && needs.plan.outputs.publishing == 'true' && (needs.build-global-artifacts.result == 'skipped' || needs.build-global-artifacts.result == 'success') && (needs.custom-build-binaries.result == 'skipped' || needs.custom-build-binaries.result == 'success') && (needs.custom-build-docker.result == 'skipped' || needs.custom-build-docker.result == 'success') && (needs.custom-build-wasm.result == 'skipped' || needs.custom-build-wasm.result == 'success') }}
|
||||
if: ${{ always() && needs.plan.result == 'success' && needs.plan.outputs.publishing == 'true' && (needs.build-global-artifacts.result == 'skipped' || needs.build-global-artifacts.result == 'success') && (needs.custom-build-binaries.result == 'skipped' || needs.custom-build-binaries.result == 'success') && (needs.custom-build-docker.result == 'skipped' || needs.custom-build-docker.result == 'success') }}
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
runs-on: "depot-ubuntu-latest-4"
|
||||
|
||||
4
.github/workflows/ty-ecosystem-analyzer.yaml
vendored
4
.github/workflows/ty-ecosystem-analyzer.yaml
vendored
@@ -40,12 +40,12 @@ jobs:
|
||||
- name: Install the latest version of uv
|
||||
uses: astral-sh/setup-uv@681c641aba71e4a1c380be3ab5e12ad51f415867 # v7.1.6
|
||||
with:
|
||||
enable-cache: true
|
||||
enable-cache: true # zizmor: ignore[cache-poisoning] acceptable risk for CloudFlare pages artifact
|
||||
|
||||
- uses: Swatinem/rust-cache@779680da715d629ac1d338a641029a2f4372abb5 # v2.8.2
|
||||
with:
|
||||
workspaces: "ruff"
|
||||
lookup-only: false
|
||||
lookup-only: false # zizmor: ignore[cache-poisoning] acceptable risk for CloudFlare pages artifact
|
||||
|
||||
- name: Install Rust toolchain
|
||||
run: rustup show
|
||||
|
||||
@@ -125,7 +125,6 @@ repos:
|
||||
args:
|
||||
- "-ignore=SC2129" # ignorable stylistic lint from shellcheck
|
||||
- "-ignore=SC2016" # another shellcheck lint: seems to have false positives?
|
||||
language: golang # means renovate will also update `additional_dependencies`
|
||||
additional_dependencies:
|
||||
# actionlint has a shellcheck integration which extracts shell scripts in `run:` steps from GitHub Actions
|
||||
# and checks these with shellcheck. This is arguably its most useful feature,
|
||||
|
||||
58
CHANGELOG.md
58
CHANGELOG.md
@@ -1,63 +1,5 @@
|
||||
# Changelog
|
||||
|
||||
## 0.14.11
|
||||
|
||||
Released on 2026-01-08.
|
||||
|
||||
### Preview features
|
||||
|
||||
- Consolidate diagnostics for matched disable/enable suppression comments ([#22099](https://github.com/astral-sh/ruff/pull/22099))
|
||||
- Report diagnostics for invalid/unmatched range suppression comments ([#21908](https://github.com/astral-sh/ruff/pull/21908))
|
||||
- \[`airflow`\] Passing positional argument into `airflow.lineage.hook.HookLineageCollector.create_asset` is not allowed (`AIR303`) ([#22046](https://github.com/astral-sh/ruff/pull/22046))
|
||||
- \[`refurb`\] Mark `FURB192` fix as always unsafe ([#22210](https://github.com/astral-sh/ruff/pull/22210))
|
||||
- \[`ruff`\] Add `non-empty-init-module` (`RUF067`) ([#22143](https://github.com/astral-sh/ruff/pull/22143))
|
||||
|
||||
### Bug fixes
|
||||
|
||||
- Fix GitHub format for multi-line diagnostics ([#22108](https://github.com/astral-sh/ruff/pull/22108))
|
||||
- \[`flake8-unused-arguments`\] Mark `**kwargs` in `TypeVar` as used (`ARG001`) ([#22214](https://github.com/astral-sh/ruff/pull/22214))
|
||||
|
||||
### Rule changes
|
||||
|
||||
- Add `help:` subdiagnostics for several Ruff rules that can sometimes appear to disagree with `ty` ([#22331](https://github.com/astral-sh/ruff/pull/22331))
|
||||
- \[`pylint`\] Demote `PLW1510` fix to display-only ([#22318](https://github.com/astral-sh/ruff/pull/22318))
|
||||
- \[`pylint`\] Ignore identical members (`PLR1714`) ([#22220](https://github.com/astral-sh/ruff/pull/22220))
|
||||
- \[`pylint`\] Improve diagnostic range for `PLC0206` ([#22312](https://github.com/astral-sh/ruff/pull/22312))
|
||||
- \[`ruff`\] Improve fix title for `RUF102` invalid rule code ([#22100](https://github.com/astral-sh/ruff/pull/22100))
|
||||
- \[`flake8-simplify`\]: Avoid unnecessary builtins import for `SIM105` ([#22358](https://github.com/astral-sh/ruff/pull/22358))
|
||||
|
||||
### Configuration
|
||||
|
||||
- Allow Python 3.15 as valid `target-version` value in preview ([#22419](https://github.com/astral-sh/ruff/pull/22419))
|
||||
- Check `required-version` before parsing rules ([#22410](https://github.com/astral-sh/ruff/pull/22410))
|
||||
- Include configured `src` directories when resolving graphs ([#22451](https://github.com/astral-sh/ruff/pull/22451))
|
||||
|
||||
### Documentation
|
||||
|
||||
- Update `T201` suggestion to not use root logger to satisfy `LOG015` ([#22059](https://github.com/astral-sh/ruff/pull/22059))
|
||||
- Fix `iter` example in unsafe fixes doc ([#22118](https://github.com/astral-sh/ruff/pull/22118))
|
||||
- \[`flake8_print`\] better suggestion for `basicConfig` in `T201` docs ([#22101](https://github.com/astral-sh/ruff/pull/22101))
|
||||
- \[`pylint`\] Restore the fix safety docs for `PLW0133` ([#22211](https://github.com/astral-sh/ruff/pull/22211))
|
||||
- Fix Jupyter notebook discovery info for editors ([#22447](https://github.com/astral-sh/ruff/pull/22447))
|
||||
|
||||
### Contributors
|
||||
|
||||
- [@charliermarsh](https://github.com/charliermarsh)
|
||||
- [@ntBre](https://github.com/ntBre)
|
||||
- [@cenviity](https://github.com/cenviity)
|
||||
- [@njhearp](https://github.com/njhearp)
|
||||
- [@cbachhuber](https://github.com/cbachhuber)
|
||||
- [@jelle-openai](https://github.com/jelle-openai)
|
||||
- [@AlexWaygood](https://github.com/AlexWaygood)
|
||||
- [@ValdonVitija](https://github.com/ValdonVitija)
|
||||
- [@BurntSushi](https://github.com/BurntSushi)
|
||||
- [@Jkhall81](https://github.com/Jkhall81)
|
||||
- [@PeterJCLaw](https://github.com/PeterJCLaw)
|
||||
- [@harupy](https://github.com/harupy)
|
||||
- [@amyreese](https://github.com/amyreese)
|
||||
- [@sjyangkevin](https://github.com/sjyangkevin)
|
||||
- [@woodruffw](https://github.com/woodruffw)
|
||||
|
||||
## 0.14.10
|
||||
|
||||
Released on 2025-12-18.
|
||||
|
||||
@@ -10,12 +10,6 @@ Run all tests (using `nextest` for faster execution):
|
||||
cargo nextest run
|
||||
```
|
||||
|
||||
For faster test execution, use the `fast-test` profile which enables optimizations while retaining debug info:
|
||||
|
||||
```sh
|
||||
cargo nextest run --cargo-profile fast-test
|
||||
```
|
||||
|
||||
Run tests for a specific crate:
|
||||
|
||||
```sh
|
||||
|
||||
16
Cargo.lock
generated
16
Cargo.lock
generated
@@ -2912,7 +2912,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ruff"
|
||||
version = "0.14.11"
|
||||
version = "0.14.10"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"argfile",
|
||||
@@ -2928,7 +2928,6 @@ dependencies = [
|
||||
"filetime",
|
||||
"globwalk",
|
||||
"ignore",
|
||||
"indexmap",
|
||||
"indoc",
|
||||
"insta",
|
||||
"insta-cmd",
|
||||
@@ -3172,7 +3171,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ruff_linter"
|
||||
version = "0.14.11"
|
||||
version = "0.14.10"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"anyhow",
|
||||
@@ -3530,7 +3529,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ruff_wasm"
|
||||
version = "0.14.11"
|
||||
version = "0.14.10"
|
||||
dependencies = [
|
||||
"console_error_panic_hook",
|
||||
"console_log",
|
||||
@@ -3646,7 +3645,7 @@ checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
|
||||
[[package]]
|
||||
name = "salsa"
|
||||
version = "0.25.2"
|
||||
source = "git+https://github.com/salsa-rs/salsa.git?rev=9860ff6ca0f1f8f3a8d6b832020002790b501254#9860ff6ca0f1f8f3a8d6b832020002790b501254"
|
||||
source = "git+https://github.com/salsa-rs/salsa.git?rev=309c249088fdeef0129606fa34ec2eefc74736ff#309c249088fdeef0129606fa34ec2eefc74736ff"
|
||||
dependencies = [
|
||||
"boxcar",
|
||||
"compact_str",
|
||||
@@ -3671,12 +3670,12 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "salsa-macro-rules"
|
||||
version = "0.25.2"
|
||||
source = "git+https://github.com/salsa-rs/salsa.git?rev=9860ff6ca0f1f8f3a8d6b832020002790b501254#9860ff6ca0f1f8f3a8d6b832020002790b501254"
|
||||
source = "git+https://github.com/salsa-rs/salsa.git?rev=309c249088fdeef0129606fa34ec2eefc74736ff#309c249088fdeef0129606fa34ec2eefc74736ff"
|
||||
|
||||
[[package]]
|
||||
name = "salsa-macros"
|
||||
version = "0.25.2"
|
||||
source = "git+https://github.com/salsa-rs/salsa.git?rev=9860ff6ca0f1f8f3a8d6b832020002790b501254#9860ff6ca0f1f8f3a8d6b832020002790b501254"
|
||||
source = "git+https://github.com/salsa-rs/salsa.git?rev=309c249088fdeef0129606fa34ec2eefc74736ff#309c249088fdeef0129606fa34ec2eefc74736ff"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -4444,7 +4443,6 @@ version = "0.0.0"
|
||||
dependencies = [
|
||||
"bitflags 2.10.0",
|
||||
"camino",
|
||||
"compact_str",
|
||||
"get-size2",
|
||||
"insta",
|
||||
"itertools 0.14.0",
|
||||
@@ -4513,13 +4511,11 @@ dependencies = [
|
||||
"regex-automata",
|
||||
"ruff_cache",
|
||||
"ruff_db",
|
||||
"ruff_diagnostics",
|
||||
"ruff_macros",
|
||||
"ruff_memory_usage",
|
||||
"ruff_options_metadata",
|
||||
"ruff_python_ast",
|
||||
"ruff_python_formatter",
|
||||
"ruff_python_trivia",
|
||||
"ruff_text_size",
|
||||
"rustc-hash",
|
||||
"salsa",
|
||||
|
||||
@@ -150,7 +150,7 @@ regex-automata = { version = "0.4.9" }
|
||||
rustc-hash = { version = "2.0.0" }
|
||||
rustc-stable-hash = { version = "0.1.2" }
|
||||
# When updating salsa, make sure to also update the revision in `fuzz/Cargo.toml`
|
||||
salsa = { git = "https://github.com/salsa-rs/salsa.git", rev = "9860ff6ca0f1f8f3a8d6b832020002790b501254", default-features = false, features = [
|
||||
salsa = { git = "https://github.com/salsa-rs/salsa.git", rev = "309c249088fdeef0129606fa34ec2eefc74736ff", default-features = false, features = [
|
||||
"compact_str",
|
||||
"macros",
|
||||
"salsa_unstable",
|
||||
@@ -335,11 +335,6 @@ strip = false
|
||||
debug = "full"
|
||||
lto = false
|
||||
|
||||
# Profile for faster iteration: applies minimal optimizations for faster tests.
|
||||
[profile.fast-test]
|
||||
inherits = "dev"
|
||||
opt-level = 1
|
||||
|
||||
# The profile that 'cargo dist' will build with.
|
||||
[profile.dist]
|
||||
inherits = "release"
|
||||
|
||||
@@ -150,8 +150,8 @@ curl -LsSf https://astral.sh/ruff/install.sh | sh
|
||||
powershell -c "irm https://astral.sh/ruff/install.ps1 | iex"
|
||||
|
||||
# For a specific version.
|
||||
curl -LsSf https://astral.sh/ruff/0.14.11/install.sh | sh
|
||||
powershell -c "irm https://astral.sh/ruff/0.14.11/install.ps1 | iex"
|
||||
curl -LsSf https://astral.sh/ruff/0.14.10/install.sh | sh
|
||||
powershell -c "irm https://astral.sh/ruff/0.14.10/install.ps1 | iex"
|
||||
```
|
||||
|
||||
You can also install Ruff via [Homebrew](https://formulae.brew.sh/formula/ruff), [Conda](https://anaconda.org/conda-forge/ruff),
|
||||
@@ -184,7 +184,7 @@ Ruff can also be used as a [pre-commit](https://pre-commit.com/) hook via [`ruff
|
||||
```yaml
|
||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||
# Ruff version.
|
||||
rev: v0.14.11
|
||||
rev: v0.14.10
|
||||
hooks:
|
||||
# Run the linter.
|
||||
- id: ruff-check
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "ruff"
|
||||
version = "0.14.11"
|
||||
version = "0.14.10"
|
||||
publish = true
|
||||
authors = { workspace = true }
|
||||
edition = { workspace = true }
|
||||
@@ -48,7 +48,6 @@ colored = { workspace = true }
|
||||
filetime = { workspace = true }
|
||||
globwalk = { workspace = true }
|
||||
ignore = { workspace = true }
|
||||
indexmap = { workspace = true }
|
||||
is-macro = { workspace = true }
|
||||
itertools = { workspace = true }
|
||||
jiff = { workspace = true }
|
||||
|
||||
@@ -2,7 +2,6 @@ use crate::args::{AnalyzeGraphArgs, ConfigArguments};
|
||||
use crate::resolve::resolve;
|
||||
use crate::{ExitStatus, resolve_default_files};
|
||||
use anyhow::Result;
|
||||
use indexmap::IndexSet;
|
||||
use log::{debug, warn};
|
||||
use path_absolutize::CWD;
|
||||
use ruff_db::system::{SystemPath, SystemPathBuf};
|
||||
@@ -12,7 +11,7 @@ use ruff_linter::source_kind::SourceKind;
|
||||
use ruff_linter::{warn_user, warn_user_once};
|
||||
use ruff_python_ast::{PySourceType, SourceType};
|
||||
use ruff_workspace::resolver::{ResolvedFile, match_exclusion, python_files_in_path};
|
||||
use rustc_hash::{FxBuildHasher, FxHashMap};
|
||||
use rustc_hash::FxHashMap;
|
||||
use std::io::Write;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::sync::{Arc, Mutex};
|
||||
@@ -60,34 +59,17 @@ pub(crate) fn analyze_graph(
|
||||
})
|
||||
.collect::<FxHashMap<_, _>>();
|
||||
|
||||
// Create a database from the source roots, combining configured `src` paths with detected
|
||||
// package roots. Configured paths are added first so they take precedence, and duplicates
|
||||
// are removed.
|
||||
let mut src_roots: IndexSet<SystemPathBuf, FxBuildHasher> = IndexSet::default();
|
||||
|
||||
// Add configured `src` paths first (for precedence), filtering to only include existing
|
||||
// directories.
|
||||
src_roots.extend(
|
||||
pyproject_config
|
||||
.settings
|
||||
.linter
|
||||
.src
|
||||
.iter()
|
||||
.filter(|path| path.is_dir())
|
||||
.filter_map(|path| SystemPathBuf::from_path_buf(path.clone()).ok()),
|
||||
);
|
||||
|
||||
// Add detected package roots.
|
||||
src_roots.extend(
|
||||
package_roots
|
||||
.values()
|
||||
.filter_map(|package| package.as_deref())
|
||||
.filter_map(|path| path.parent())
|
||||
.filter_map(|path| SystemPathBuf::from_path_buf(path.to_path_buf()).ok()),
|
||||
);
|
||||
// Create a database from the source roots.
|
||||
let src_roots = package_roots
|
||||
.values()
|
||||
.filter_map(|package| package.as_deref())
|
||||
.filter_map(|package| package.parent())
|
||||
.map(Path::to_path_buf)
|
||||
.filter_map(|path| SystemPathBuf::from_path_buf(path).ok())
|
||||
.collect();
|
||||
|
||||
let db = ModuleDb::from_src_roots(
|
||||
src_roots.into_iter().collect(),
|
||||
src_roots,
|
||||
pyproject_config
|
||||
.settings
|
||||
.analyze
|
||||
|
||||
@@ -29,10 +29,10 @@ pub(crate) fn show_settings(
|
||||
bail!("No files found under the given path");
|
||||
};
|
||||
|
||||
let (settings, config_path) = resolver.resolve_with_path(&path);
|
||||
let settings = resolver.resolve(&path);
|
||||
|
||||
writeln!(writer, "Resolved settings for: \"{}\"", path.display())?;
|
||||
if let Some(settings_path) = config_path {
|
||||
if let Some(settings_path) = pyproject_config.path.as_ref() {
|
||||
writeln!(writer, "Settings path: \"{}\"", settings_path.display())?;
|
||||
}
|
||||
write!(writer, "{settings}")?;
|
||||
|
||||
@@ -714,121 +714,6 @@ fn notebook_basic() -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Test that the `src` configuration option is respected.
|
||||
///
|
||||
/// This is useful for monorepos where there are multiple source directories that need to be
|
||||
/// included in the module resolution search path.
|
||||
#[test]
|
||||
fn src_option() -> Result<()> {
|
||||
let tempdir = TempDir::new()?;
|
||||
let root = ChildPath::new(tempdir.path());
|
||||
|
||||
// Create a lib directory with a package.
|
||||
root.child("lib")
|
||||
.child("mylib")
|
||||
.child("__init__.py")
|
||||
.write_str("def helper(): pass")?;
|
||||
|
||||
// Create an app directory with a file that imports from mylib.
|
||||
root.child("app").child("__init__.py").write_str("")?;
|
||||
root.child("app")
|
||||
.child("main.py")
|
||||
.write_str("from mylib import helper")?;
|
||||
|
||||
// Without src configured, the import from mylib won't resolve.
|
||||
insta::with_settings!({
|
||||
filters => INSTA_FILTERS.to_vec(),
|
||||
}, {
|
||||
assert_cmd_snapshot!(command().arg("app").current_dir(&root), @r#"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
{
|
||||
"app/__init__.py": [],
|
||||
"app/main.py": []
|
||||
}
|
||||
|
||||
----- stderr -----
|
||||
"#);
|
||||
});
|
||||
|
||||
// With src = ["lib"], the import should resolve.
|
||||
root.child("ruff.toml").write_str(indoc::indoc! {r#"
|
||||
src = ["lib"]
|
||||
"#})?;
|
||||
|
||||
insta::with_settings!({
|
||||
filters => INSTA_FILTERS.to_vec(),
|
||||
}, {
|
||||
assert_cmd_snapshot!(command().arg("app").current_dir(&root), @r#"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
{
|
||||
"app/__init__.py": [],
|
||||
"app/main.py": [
|
||||
"lib/mylib/__init__.py"
|
||||
]
|
||||
}
|
||||
|
||||
----- stderr -----
|
||||
"#);
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Test that glob patterns in `src` are expanded.
|
||||
#[test]
|
||||
fn src_glob_expansion() -> Result<()> {
|
||||
let tempdir = TempDir::new()?;
|
||||
let root = ChildPath::new(tempdir.path());
|
||||
|
||||
// Create multiple lib directories with packages.
|
||||
root.child("libs")
|
||||
.child("lib_a")
|
||||
.child("pkg_a")
|
||||
.child("__init__.py")
|
||||
.write_str("def func_a(): pass")?;
|
||||
root.child("libs")
|
||||
.child("lib_b")
|
||||
.child("pkg_b")
|
||||
.child("__init__.py")
|
||||
.write_str("def func_b(): pass")?;
|
||||
|
||||
// Create an app that imports from both packages.
|
||||
root.child("app").child("__init__.py").write_str("")?;
|
||||
root.child("app")
|
||||
.child("main.py")
|
||||
.write_str("from pkg_a import func_a\nfrom pkg_b import func_b")?;
|
||||
|
||||
// Use a glob pattern to include all lib directories.
|
||||
root.child("ruff.toml").write_str(indoc::indoc! {r#"
|
||||
src = ["libs/*"]
|
||||
"#})?;
|
||||
|
||||
insta::with_settings!({
|
||||
filters => INSTA_FILTERS.to_vec(),
|
||||
}, {
|
||||
assert_cmd_snapshot!(command().arg("app").current_dir(&root), @r#"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
{
|
||||
"app/__init__.py": [],
|
||||
"app/main.py": [
|
||||
"libs/lib_a/pkg_a/__init__.py",
|
||||
"libs/lib_b/pkg_b/__init__.py"
|
||||
]
|
||||
}
|
||||
|
||||
----- stderr -----
|
||||
"#);
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn notebook_with_magic() -> Result<()> {
|
||||
let tempdir = TempDir::new()?;
|
||||
|
||||
@@ -1126,35 +1126,6 @@ import os
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn required_version_fails_to_parse() -> Result<()> {
|
||||
let fixture = CliTest::with_file(
|
||||
"ruff.toml",
|
||||
r#"
|
||||
required-version = "pikachu"
|
||||
"#,
|
||||
)?;
|
||||
assert_cmd_snapshot!(fixture
|
||||
.check_command(), @r#"
|
||||
success: false
|
||||
exit_code: 2
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
ruff failed
|
||||
Cause: Failed to load configuration `[TMP]/ruff.toml`
|
||||
Cause: Failed to parse [TMP]/ruff.toml
|
||||
Cause: TOML parse error at line 2, column 20
|
||||
|
|
||||
2 | required-version = "pikachu"
|
||||
| ^^^^^^^^^
|
||||
Failed to parse version: Unexpected end of version specifier, expected operator:
|
||||
pikachu
|
||||
^^^^^^^
|
||||
"#);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn required_version_exact_mismatch() -> Result<()> {
|
||||
let version = env!("CARGO_PKG_VERSION");
|
||||
@@ -1166,10 +1137,10 @@ required-version = "0.1.0"
|
||||
"#,
|
||||
)?;
|
||||
|
||||
let mut settings = insta::Settings::clone_current();
|
||||
settings.add_filter(version, "[VERSION]");
|
||||
settings.bind(|| {
|
||||
assert_cmd_snapshot!(fixture
|
||||
insta::with_settings!({
|
||||
filters => vec![(version, "[VERSION]")]
|
||||
}, {
|
||||
assert_cmd_snapshot!(fixture
|
||||
.check_command()
|
||||
.arg("--config")
|
||||
.arg("ruff.toml")
|
||||
@@ -1183,7 +1154,6 @@ import os
|
||||
|
||||
----- stderr -----
|
||||
ruff failed
|
||||
Cause: Failed to load configuration `[TMP]/ruff.toml`
|
||||
Cause: Required version `==0.1.0` does not match the running version `[VERSION]`
|
||||
");
|
||||
});
|
||||
@@ -1242,10 +1212,10 @@ required-version = ">{version}"
|
||||
),
|
||||
)?;
|
||||
|
||||
let mut settings = insta::Settings::clone_current();
|
||||
settings.add_filter(version, "[VERSION]");
|
||||
settings.bind(|| {
|
||||
assert_cmd_snapshot!(fixture
|
||||
insta::with_settings!({
|
||||
filters => vec![(version, "[VERSION]")]
|
||||
}, {
|
||||
assert_cmd_snapshot!(fixture
|
||||
.check_command()
|
||||
.arg("--config")
|
||||
.arg("ruff.toml")
|
||||
@@ -1259,48 +1229,6 @@ import os
|
||||
|
||||
----- stderr -----
|
||||
ruff failed
|
||||
Cause: Failed to load configuration `[TMP]/ruff.toml`
|
||||
Cause: Required version `>[VERSION]` does not match the running version `[VERSION]`
|
||||
");
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn required_version_precedes_rule_validation() -> Result<()> {
|
||||
let version = env!("CARGO_PKG_VERSION");
|
||||
|
||||
let fixture = CliTest::with_file(
|
||||
"ruff.toml",
|
||||
&format!(
|
||||
r#"
|
||||
required-version = ">{version}"
|
||||
|
||||
[lint]
|
||||
select = ["RUF999"]
|
||||
"#
|
||||
),
|
||||
)?;
|
||||
|
||||
let mut settings = insta::Settings::clone_current();
|
||||
settings.add_filter(version, "[VERSION]");
|
||||
settings.bind(|| {
|
||||
assert_cmd_snapshot!(fixture
|
||||
.check_command()
|
||||
.arg("--config")
|
||||
.arg("ruff.toml")
|
||||
.arg("-")
|
||||
.pass_stdin(r#"
|
||||
import os
|
||||
"#), @"
|
||||
success: false
|
||||
exit_code: 2
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
ruff failed
|
||||
Cause: Failed to load configuration `[TMP]/ruff.toml`
|
||||
Cause: Required version `>[VERSION]` does not match the running version `[VERSION]`
|
||||
");
|
||||
});
|
||||
|
||||
@@ -16,7 +16,6 @@ success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
Resolved settings for: "[TMP]/foo/test.py"
|
||||
Settings path: "[TMP]/foo/pyproject.toml"
|
||||
|
||||
# General Settings
|
||||
cache_dir = "[TMP]/foo/.ruff_cache"
|
||||
|
||||
@@ -50,56 +50,6 @@ ignore = [
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn display_settings_from_nested_directory() -> anyhow::Result<()> {
|
||||
let tempdir = TempDir::new().context("Failed to create temp directory.")?;
|
||||
|
||||
// Tempdir path's on macos are symlinks, which doesn't play nicely with
|
||||
// our snapshot filtering.
|
||||
let project_dir =
|
||||
dunce::canonicalize(tempdir.path()).context("Failed to canonical tempdir path.")?;
|
||||
|
||||
// Root pyproject.toml.
|
||||
std::fs::write(
|
||||
project_dir.join("pyproject.toml"),
|
||||
r#"
|
||||
[tool.ruff]
|
||||
line-length = 100
|
||||
|
||||
[tool.ruff.lint]
|
||||
select = ["E", "F"]
|
||||
"#,
|
||||
)?;
|
||||
|
||||
// Create a subdirectory with its own pyproject.toml.
|
||||
let subdir = project_dir.join("subdir");
|
||||
std::fs::create_dir(&subdir)?;
|
||||
|
||||
std::fs::write(
|
||||
subdir.join("pyproject.toml"),
|
||||
r#"
|
||||
[tool.ruff]
|
||||
line-length = 120
|
||||
|
||||
[tool.ruff.lint]
|
||||
select = ["E", "F", "I"]
|
||||
"#,
|
||||
)?;
|
||||
|
||||
std::fs::write(subdir.join("test.py"), r#"import os"#).context("Failed to write test.py.")?;
|
||||
|
||||
insta::with_settings!({filters => vec![
|
||||
(&*tempdir_filter(&project_dir), "<temp_dir>/"),
|
||||
(r#"\\(\w\w|\s|\.|")"#, "/$1"),
|
||||
]}, {
|
||||
assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
|
||||
.args(["check", "--show-settings", "subdir/test.py"])
|
||||
.current_dir(&project_dir));
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn tempdir_filter(project_dir: &Path) -> String {
|
||||
format!(r#"{}\\?/?"#, regex::escape(project_dir.to_str().unwrap()))
|
||||
}
|
||||
|
||||
@@ -1,410 +0,0 @@
|
||||
---
|
||||
source: crates/ruff/tests/show_settings.rs
|
||||
info:
|
||||
program: ruff
|
||||
args:
|
||||
- check
|
||||
- "--show-settings"
|
||||
- subdir/test.py
|
||||
---
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
Resolved settings for: "<temp_dir>/subdir/test.py"
|
||||
Settings path: "<temp_dir>/subdir/pyproject.toml"
|
||||
|
||||
# General Settings
|
||||
cache_dir = "<temp_dir>/subdir/.ruff_cache"
|
||||
fix = false
|
||||
fix_only = false
|
||||
output_format = full
|
||||
show_fixes = false
|
||||
unsafe_fixes = hint
|
||||
|
||||
# File Resolver Settings
|
||||
file_resolver.exclude = [
|
||||
".bzr",
|
||||
".direnv",
|
||||
".eggs",
|
||||
".git",
|
||||
".git-rewrite",
|
||||
".hg",
|
||||
".ipynb_checkpoints",
|
||||
".mypy_cache",
|
||||
".nox",
|
||||
".pants.d",
|
||||
".pyenv",
|
||||
".pytest_cache",
|
||||
".pytype",
|
||||
".ruff_cache",
|
||||
".svn",
|
||||
".tox",
|
||||
".venv",
|
||||
".vscode",
|
||||
"__pypackages__",
|
||||
"_build",
|
||||
"buck-out",
|
||||
"dist",
|
||||
"node_modules",
|
||||
"site-packages",
|
||||
"venv",
|
||||
]
|
||||
file_resolver.extend_exclude = []
|
||||
file_resolver.force_exclude = false
|
||||
file_resolver.include = [
|
||||
"*.py",
|
||||
"*.pyi",
|
||||
"*.ipynb",
|
||||
"**/pyproject.toml",
|
||||
]
|
||||
file_resolver.extend_include = []
|
||||
file_resolver.respect_gitignore = true
|
||||
file_resolver.project_root = "<temp_dir>/subdir"
|
||||
|
||||
# Linter Settings
|
||||
linter.exclude = []
|
||||
linter.project_root = "<temp_dir>/subdir"
|
||||
linter.rules.enabled = [
|
||||
unsorted-imports (I001),
|
||||
missing-required-import (I002),
|
||||
mixed-spaces-and-tabs (E101),
|
||||
multiple-imports-on-one-line (E401),
|
||||
module-import-not-at-top-of-file (E402),
|
||||
line-too-long (E501),
|
||||
multiple-statements-on-one-line-colon (E701),
|
||||
multiple-statements-on-one-line-semicolon (E702),
|
||||
useless-semicolon (E703),
|
||||
none-comparison (E711),
|
||||
true-false-comparison (E712),
|
||||
not-in-test (E713),
|
||||
not-is-test (E714),
|
||||
type-comparison (E721),
|
||||
bare-except (E722),
|
||||
lambda-assignment (E731),
|
||||
ambiguous-variable-name (E741),
|
||||
ambiguous-class-name (E742),
|
||||
ambiguous-function-name (E743),
|
||||
io-error (E902),
|
||||
unused-import (F401),
|
||||
import-shadowed-by-loop-var (F402),
|
||||
undefined-local-with-import-star (F403),
|
||||
late-future-import (F404),
|
||||
undefined-local-with-import-star-usage (F405),
|
||||
undefined-local-with-nested-import-star-usage (F406),
|
||||
future-feature-not-defined (F407),
|
||||
percent-format-invalid-format (F501),
|
||||
percent-format-expected-mapping (F502),
|
||||
percent-format-expected-sequence (F503),
|
||||
percent-format-extra-named-arguments (F504),
|
||||
percent-format-missing-argument (F505),
|
||||
percent-format-mixed-positional-and-named (F506),
|
||||
percent-format-positional-count-mismatch (F507),
|
||||
percent-format-star-requires-sequence (F508),
|
||||
percent-format-unsupported-format-character (F509),
|
||||
string-dot-format-invalid-format (F521),
|
||||
string-dot-format-extra-named-arguments (F522),
|
||||
string-dot-format-extra-positional-arguments (F523),
|
||||
string-dot-format-missing-arguments (F524),
|
||||
string-dot-format-mixing-automatic (F525),
|
||||
f-string-missing-placeholders (F541),
|
||||
multi-value-repeated-key-literal (F601),
|
||||
multi-value-repeated-key-variable (F602),
|
||||
expressions-in-star-assignment (F621),
|
||||
multiple-starred-expressions (F622),
|
||||
assert-tuple (F631),
|
||||
is-literal (F632),
|
||||
invalid-print-syntax (F633),
|
||||
if-tuple (F634),
|
||||
break-outside-loop (F701),
|
||||
continue-outside-loop (F702),
|
||||
yield-outside-function (F704),
|
||||
return-outside-function (F706),
|
||||
default-except-not-last (F707),
|
||||
forward-annotation-syntax-error (F722),
|
||||
redefined-while-unused (F811),
|
||||
undefined-name (F821),
|
||||
undefined-export (F822),
|
||||
undefined-local (F823),
|
||||
unused-variable (F841),
|
||||
unused-annotation (F842),
|
||||
raise-not-implemented (F901),
|
||||
]
|
||||
linter.rules.should_fix = [
|
||||
unsorted-imports (I001),
|
||||
missing-required-import (I002),
|
||||
mixed-spaces-and-tabs (E101),
|
||||
multiple-imports-on-one-line (E401),
|
||||
module-import-not-at-top-of-file (E402),
|
||||
line-too-long (E501),
|
||||
multiple-statements-on-one-line-colon (E701),
|
||||
multiple-statements-on-one-line-semicolon (E702),
|
||||
useless-semicolon (E703),
|
||||
none-comparison (E711),
|
||||
true-false-comparison (E712),
|
||||
not-in-test (E713),
|
||||
not-is-test (E714),
|
||||
type-comparison (E721),
|
||||
bare-except (E722),
|
||||
lambda-assignment (E731),
|
||||
ambiguous-variable-name (E741),
|
||||
ambiguous-class-name (E742),
|
||||
ambiguous-function-name (E743),
|
||||
io-error (E902),
|
||||
unused-import (F401),
|
||||
import-shadowed-by-loop-var (F402),
|
||||
undefined-local-with-import-star (F403),
|
||||
late-future-import (F404),
|
||||
undefined-local-with-import-star-usage (F405),
|
||||
undefined-local-with-nested-import-star-usage (F406),
|
||||
future-feature-not-defined (F407),
|
||||
percent-format-invalid-format (F501),
|
||||
percent-format-expected-mapping (F502),
|
||||
percent-format-expected-sequence (F503),
|
||||
percent-format-extra-named-arguments (F504),
|
||||
percent-format-missing-argument (F505),
|
||||
percent-format-mixed-positional-and-named (F506),
|
||||
percent-format-positional-count-mismatch (F507),
|
||||
percent-format-star-requires-sequence (F508),
|
||||
percent-format-unsupported-format-character (F509),
|
||||
string-dot-format-invalid-format (F521),
|
||||
string-dot-format-extra-named-arguments (F522),
|
||||
string-dot-format-extra-positional-arguments (F523),
|
||||
string-dot-format-missing-arguments (F524),
|
||||
string-dot-format-mixing-automatic (F525),
|
||||
f-string-missing-placeholders (F541),
|
||||
multi-value-repeated-key-literal (F601),
|
||||
multi-value-repeated-key-variable (F602),
|
||||
expressions-in-star-assignment (F621),
|
||||
multiple-starred-expressions (F622),
|
||||
assert-tuple (F631),
|
||||
is-literal (F632),
|
||||
invalid-print-syntax (F633),
|
||||
if-tuple (F634),
|
||||
break-outside-loop (F701),
|
||||
continue-outside-loop (F702),
|
||||
yield-outside-function (F704),
|
||||
return-outside-function (F706),
|
||||
default-except-not-last (F707),
|
||||
forward-annotation-syntax-error (F722),
|
||||
redefined-while-unused (F811),
|
||||
undefined-name (F821),
|
||||
undefined-export (F822),
|
||||
undefined-local (F823),
|
||||
unused-variable (F841),
|
||||
unused-annotation (F842),
|
||||
raise-not-implemented (F901),
|
||||
]
|
||||
linter.per_file_ignores = {}
|
||||
linter.safety_table.forced_safe = []
|
||||
linter.safety_table.forced_unsafe = []
|
||||
linter.unresolved_target_version = none
|
||||
linter.per_file_target_version = {}
|
||||
linter.preview = disabled
|
||||
linter.explicit_preview_rules = false
|
||||
linter.extension = ExtensionMapping({})
|
||||
linter.allowed_confusables = []
|
||||
linter.builtins = []
|
||||
linter.dummy_variable_rgx = ^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$
|
||||
linter.external = []
|
||||
linter.ignore_init_module_imports = true
|
||||
linter.logger_objects = []
|
||||
linter.namespace_packages = []
|
||||
linter.src = [
|
||||
"<temp_dir>/subdir",
|
||||
"<temp_dir>/subdir/src",
|
||||
]
|
||||
linter.tab_size = 4
|
||||
linter.line_length = 120
|
||||
linter.task_tags = [
|
||||
TODO,
|
||||
FIXME,
|
||||
XXX,
|
||||
]
|
||||
linter.typing_modules = []
|
||||
linter.typing_extensions = true
|
||||
|
||||
# Linter Plugins
|
||||
linter.flake8_annotations.mypy_init_return = false
|
||||
linter.flake8_annotations.suppress_dummy_args = false
|
||||
linter.flake8_annotations.suppress_none_returning = false
|
||||
linter.flake8_annotations.allow_star_arg_any = false
|
||||
linter.flake8_annotations.ignore_fully_untyped = false
|
||||
linter.flake8_bandit.hardcoded_tmp_directory = [
|
||||
/tmp,
|
||||
/var/tmp,
|
||||
/dev/shm,
|
||||
]
|
||||
linter.flake8_bandit.check_typed_exception = false
|
||||
linter.flake8_bandit.extend_markup_names = []
|
||||
linter.flake8_bandit.allowed_markup_calls = []
|
||||
linter.flake8_bugbear.extend_immutable_calls = []
|
||||
linter.flake8_builtins.allowed_modules = []
|
||||
linter.flake8_builtins.ignorelist = []
|
||||
linter.flake8_builtins.strict_checking = false
|
||||
linter.flake8_comprehensions.allow_dict_calls_with_keyword_arguments = false
|
||||
linter.flake8_copyright.notice_rgx = (?i)Copyright\s+((?:\(C\)|©)\s+)?\d{4}((-|,\s)\d{4})*
|
||||
linter.flake8_copyright.author = none
|
||||
linter.flake8_copyright.min_file_size = 0
|
||||
linter.flake8_errmsg.max_string_length = 0
|
||||
linter.flake8_gettext.function_names = [
|
||||
_,
|
||||
gettext,
|
||||
ngettext,
|
||||
]
|
||||
linter.flake8_implicit_str_concat.allow_multiline = true
|
||||
linter.flake8_import_conventions.aliases = {
|
||||
altair = alt,
|
||||
holoviews = hv,
|
||||
matplotlib = mpl,
|
||||
matplotlib.pyplot = plt,
|
||||
networkx = nx,
|
||||
numpy = np,
|
||||
numpy.typing = npt,
|
||||
pandas = pd,
|
||||
panel = pn,
|
||||
plotly.express = px,
|
||||
polars = pl,
|
||||
pyarrow = pa,
|
||||
seaborn = sns,
|
||||
tensorflow = tf,
|
||||
tkinter = tk,
|
||||
xml.etree.ElementTree = ET,
|
||||
}
|
||||
linter.flake8_import_conventions.banned_aliases = {}
|
||||
linter.flake8_import_conventions.banned_from = []
|
||||
linter.flake8_pytest_style.fixture_parentheses = false
|
||||
linter.flake8_pytest_style.parametrize_names_type = tuple
|
||||
linter.flake8_pytest_style.parametrize_values_type = list
|
||||
linter.flake8_pytest_style.parametrize_values_row_type = tuple
|
||||
linter.flake8_pytest_style.raises_require_match_for = [
|
||||
BaseException,
|
||||
Exception,
|
||||
ValueError,
|
||||
OSError,
|
||||
IOError,
|
||||
EnvironmentError,
|
||||
socket.error,
|
||||
]
|
||||
linter.flake8_pytest_style.raises_extend_require_match_for = []
|
||||
linter.flake8_pytest_style.mark_parentheses = false
|
||||
linter.flake8_quotes.inline_quotes = double
|
||||
linter.flake8_quotes.multiline_quotes = double
|
||||
linter.flake8_quotes.docstring_quotes = double
|
||||
linter.flake8_quotes.avoid_escape = true
|
||||
linter.flake8_self.ignore_names = [
|
||||
_make,
|
||||
_asdict,
|
||||
_replace,
|
||||
_fields,
|
||||
_field_defaults,
|
||||
_name_,
|
||||
_value_,
|
||||
]
|
||||
linter.flake8_tidy_imports.ban_relative_imports = "parents"
|
||||
linter.flake8_tidy_imports.banned_api = {}
|
||||
linter.flake8_tidy_imports.banned_module_level_imports = []
|
||||
linter.flake8_type_checking.strict = false
|
||||
linter.flake8_type_checking.exempt_modules = [
|
||||
typing,
|
||||
typing_extensions,
|
||||
]
|
||||
linter.flake8_type_checking.runtime_required_base_classes = []
|
||||
linter.flake8_type_checking.runtime_required_decorators = []
|
||||
linter.flake8_type_checking.quote_annotations = false
|
||||
linter.flake8_unused_arguments.ignore_variadic_names = false
|
||||
linter.isort.required_imports = []
|
||||
linter.isort.combine_as_imports = false
|
||||
linter.isort.force_single_line = false
|
||||
linter.isort.force_sort_within_sections = false
|
||||
linter.isort.detect_same_package = true
|
||||
linter.isort.case_sensitive = false
|
||||
linter.isort.force_wrap_aliases = false
|
||||
linter.isort.force_to_top = []
|
||||
linter.isort.known_modules = {}
|
||||
linter.isort.order_by_type = true
|
||||
linter.isort.relative_imports_order = furthest_to_closest
|
||||
linter.isort.single_line_exclusions = []
|
||||
linter.isort.split_on_trailing_comma = true
|
||||
linter.isort.classes = []
|
||||
linter.isort.constants = []
|
||||
linter.isort.variables = []
|
||||
linter.isort.no_lines_before = []
|
||||
linter.isort.lines_after_imports = -1
|
||||
linter.isort.lines_between_types = 0
|
||||
linter.isort.forced_separate = []
|
||||
linter.isort.section_order = [
|
||||
known { type = future },
|
||||
known { type = standard_library },
|
||||
known { type = third_party },
|
||||
known { type = first_party },
|
||||
known { type = local_folder },
|
||||
]
|
||||
linter.isort.default_section = known { type = third_party }
|
||||
linter.isort.no_sections = false
|
||||
linter.isort.from_first = false
|
||||
linter.isort.length_sort = false
|
||||
linter.isort.length_sort_straight = false
|
||||
linter.mccabe.max_complexity = 10
|
||||
linter.pep8_naming.ignore_names = [
|
||||
setUp,
|
||||
tearDown,
|
||||
setUpClass,
|
||||
tearDownClass,
|
||||
setUpModule,
|
||||
tearDownModule,
|
||||
asyncSetUp,
|
||||
asyncTearDown,
|
||||
setUpTestData,
|
||||
failureException,
|
||||
longMessage,
|
||||
maxDiff,
|
||||
]
|
||||
linter.pep8_naming.classmethod_decorators = []
|
||||
linter.pep8_naming.staticmethod_decorators = []
|
||||
linter.pycodestyle.max_line_length = 120
|
||||
linter.pycodestyle.max_doc_length = none
|
||||
linter.pycodestyle.ignore_overlong_task_comments = false
|
||||
linter.pyflakes.extend_generics = []
|
||||
linter.pyflakes.allowed_unused_imports = []
|
||||
linter.pylint.allow_magic_value_types = [
|
||||
str,
|
||||
bytes,
|
||||
]
|
||||
linter.pylint.allow_dunder_method_names = []
|
||||
linter.pylint.max_args = 5
|
||||
linter.pylint.max_positional_args = 5
|
||||
linter.pylint.max_returns = 6
|
||||
linter.pylint.max_bool_expr = 5
|
||||
linter.pylint.max_branches = 12
|
||||
linter.pylint.max_statements = 50
|
||||
linter.pylint.max_public_methods = 20
|
||||
linter.pylint.max_locals = 15
|
||||
linter.pylint.max_nested_blocks = 5
|
||||
linter.pyupgrade.keep_runtime_typing = false
|
||||
linter.ruff.parenthesize_tuple_in_subscript = false
|
||||
linter.ruff.strictly_empty_init_modules = false
|
||||
|
||||
# Formatter Settings
|
||||
formatter.exclude = []
|
||||
formatter.unresolved_target_version = 3.10
|
||||
formatter.per_file_target_version = {}
|
||||
formatter.preview = disabled
|
||||
formatter.line_width = 120
|
||||
formatter.line_ending = auto
|
||||
formatter.indent_style = space
|
||||
formatter.indent_width = 4
|
||||
formatter.quote_style = double
|
||||
formatter.magic_trailing_comma = respect
|
||||
formatter.docstring_code_format = disabled
|
||||
formatter.docstring_code_line_width = dynamic
|
||||
|
||||
# Analyze Settings
|
||||
analyze.exclude = []
|
||||
analyze.preview = disabled
|
||||
analyze.target_version = 3.10
|
||||
analyze.string_imports = disabled
|
||||
analyze.extension = ExtensionMapping({})
|
||||
analyze.include_dependencies = {}
|
||||
analyze.type_checking_imports = true
|
||||
|
||||
----- stderr -----
|
||||
@@ -15,7 +15,7 @@ use ruff_db::files::{File, system_path_to_file};
|
||||
use ruff_db::source::source_text;
|
||||
use ruff_db::system::{InMemorySystem, MemoryFileSystem, SystemPath, SystemPathBuf, TestSystem};
|
||||
use ruff_python_ast::PythonVersion;
|
||||
use ty_project::metadata::options::{AnalysisOptions, EnvironmentOptions, Options};
|
||||
use ty_project::metadata::options::{EnvironmentOptions, Options};
|
||||
use ty_project::metadata::value::{RangedValue, RelativePathBuf};
|
||||
use ty_project::watch::{ChangeEvent, ChangedKind};
|
||||
use ty_project::{CheckMode, Db, ProjectDatabase, ProjectMetadata};
|
||||
@@ -67,7 +67,6 @@ fn tomllib_path(file: &TestFile) -> SystemPathBuf {
|
||||
SystemPathBuf::from("src").join(file.name())
|
||||
}
|
||||
|
||||
#[expect(clippy::needless_update)]
|
||||
fn setup_tomllib_case() -> Case {
|
||||
let system = TestSystem::default();
|
||||
let fs = system.memory_file_system().clone();
|
||||
@@ -86,10 +85,6 @@ fn setup_tomllib_case() -> Case {
|
||||
python_version: Some(RangedValue::cli(PythonVersion::PY312)),
|
||||
..EnvironmentOptions::default()
|
||||
}),
|
||||
analysis: Some(AnalysisOptions {
|
||||
respect_type_ignore_comments: Some(false),
|
||||
..AnalysisOptions::default()
|
||||
}),
|
||||
..Options::default()
|
||||
});
|
||||
|
||||
@@ -226,7 +221,7 @@ fn setup_micro_case(code: &str) -> Case {
|
||||
let file_path = "src/test.py";
|
||||
fs.write_file_all(
|
||||
SystemPathBuf::from(file_path),
|
||||
&*ruff_python_trivia::textwrap::dedent(code),
|
||||
ruff_python_trivia::textwrap::dedent(code),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
@@ -760,7 +755,7 @@ fn datetype(criterion: &mut Criterion) {
|
||||
max_dep_date: "2025-07-04",
|
||||
python_version: PythonVersion::PY313,
|
||||
},
|
||||
4,
|
||||
2,
|
||||
);
|
||||
|
||||
bench_project(&benchmark, criterion);
|
||||
|
||||
@@ -71,8 +71,6 @@ impl Display for Benchmark<'_> {
|
||||
}
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
#[expect(clippy::cast_precision_loss)]
|
||||
fn check_project(db: &ProjectDatabase, project_name: &str, max_diagnostics: usize) {
|
||||
let result = db.check();
|
||||
let diagnostics = result.len();
|
||||
@@ -81,12 +79,6 @@ fn check_project(db: &ProjectDatabase, project_name: &str, max_diagnostics: usiz
|
||||
diagnostics > 1 && diagnostics <= max_diagnostics,
|
||||
"Expected between 1 and {max_diagnostics} diagnostics on project '{project_name}' but got {diagnostics}",
|
||||
);
|
||||
|
||||
if (max_diagnostics - diagnostics) as f64 / max_diagnostics as f64 > 0.10 {
|
||||
tracing::warn!(
|
||||
"The expected diagnostics for project `{project_name}` can be reduced: expected {max_diagnostics} but got {diagnostics}"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
static ALTAIR: Benchmark = Benchmark::new(
|
||||
@@ -109,7 +101,7 @@ static ALTAIR: Benchmark = Benchmark::new(
|
||||
max_dep_date: "2025-06-17",
|
||||
python_version: PythonVersion::PY312,
|
||||
},
|
||||
850,
|
||||
1000,
|
||||
);
|
||||
|
||||
static COLOUR_SCIENCE: Benchmark = Benchmark::new(
|
||||
@@ -128,7 +120,7 @@ static COLOUR_SCIENCE: Benchmark = Benchmark::new(
|
||||
max_dep_date: "2025-06-17",
|
||||
python_version: PythonVersion::PY310,
|
||||
},
|
||||
350,
|
||||
1070,
|
||||
);
|
||||
|
||||
static FREQTRADE: Benchmark = Benchmark::new(
|
||||
@@ -171,7 +163,7 @@ static PANDAS: Benchmark = Benchmark::new(
|
||||
max_dep_date: "2025-06-17",
|
||||
python_version: PythonVersion::PY312,
|
||||
},
|
||||
3800,
|
||||
4000,
|
||||
);
|
||||
|
||||
static PYDANTIC: Benchmark = Benchmark::new(
|
||||
@@ -189,7 +181,7 @@ static PYDANTIC: Benchmark = Benchmark::new(
|
||||
max_dep_date: "2025-06-17",
|
||||
python_version: PythonVersion::PY39,
|
||||
},
|
||||
3200,
|
||||
7000,
|
||||
);
|
||||
|
||||
static SYMPY: Benchmark = Benchmark::new(
|
||||
@@ -202,7 +194,7 @@ static SYMPY: Benchmark = Benchmark::new(
|
||||
max_dep_date: "2025-06-17",
|
||||
python_version: PythonVersion::PY312,
|
||||
},
|
||||
13400,
|
||||
13116,
|
||||
);
|
||||
|
||||
static TANJUN: Benchmark = Benchmark::new(
|
||||
@@ -215,7 +207,7 @@ static TANJUN: Benchmark = Benchmark::new(
|
||||
max_dep_date: "2025-06-17",
|
||||
python_version: PythonVersion::PY312,
|
||||
},
|
||||
110,
|
||||
320,
|
||||
);
|
||||
|
||||
static STATIC_FRAME: Benchmark = Benchmark::new(
|
||||
@@ -231,7 +223,7 @@ static STATIC_FRAME: Benchmark = Benchmark::new(
|
||||
max_dep_date: "2025-08-09",
|
||||
python_version: PythonVersion::PY311,
|
||||
},
|
||||
1700,
|
||||
1100,
|
||||
);
|
||||
|
||||
#[track_caller]
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
use std::fmt::Formatter;
|
||||
use std::sync::Arc;
|
||||
use std::sync::atomic::AtomicBool;
|
||||
|
||||
@@ -50,15 +49,3 @@ impl CancellationToken {
|
||||
self.cancelled.load(std::sync::atomic::Ordering::Relaxed)
|
||||
}
|
||||
}
|
||||
|
||||
/// The operation was canceled by the provided [`CancellationToken`].
|
||||
#[derive(Debug)]
|
||||
pub struct Canceled;
|
||||
|
||||
impl std::error::Error for Canceled {}
|
||||
|
||||
impl std::fmt::Display for Canceled {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
f.write_str("operation was canceled")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,44 +98,6 @@ impl Diagnostic {
|
||||
diag
|
||||
}
|
||||
|
||||
/// Adds sub diagnostics that tell the user that this is a bug in ty
|
||||
/// and asks them to open an issue on GitHub.
|
||||
pub fn add_bug_sub_diagnostics(&mut self, url_encoded_title: &str) {
|
||||
self.sub(SubDiagnostic::new(
|
||||
SubDiagnosticSeverity::Info,
|
||||
"This indicates a bug in ty.",
|
||||
));
|
||||
|
||||
self.sub(SubDiagnostic::new(
|
||||
SubDiagnosticSeverity::Info,
|
||||
format_args!(
|
||||
"If you could open an issue at https://github.com/astral-sh/ty/issues/new?title={url_encoded_title}, we'd be very appreciative!"
|
||||
),
|
||||
));
|
||||
self.sub(SubDiagnostic::new(
|
||||
SubDiagnosticSeverity::Info,
|
||||
format!(
|
||||
"Platform: {os} {arch}",
|
||||
os = std::env::consts::OS,
|
||||
arch = std::env::consts::ARCH
|
||||
),
|
||||
));
|
||||
if let Some(version) = crate::program_version() {
|
||||
self.sub(SubDiagnostic::new(
|
||||
SubDiagnosticSeverity::Info,
|
||||
format!("Version: {version}"),
|
||||
));
|
||||
}
|
||||
|
||||
self.sub(SubDiagnostic::new(
|
||||
SubDiagnosticSeverity::Info,
|
||||
format!(
|
||||
"Args: {args:?}",
|
||||
args = std::env::args().collect::<Vec<_>>()
|
||||
),
|
||||
));
|
||||
}
|
||||
|
||||
/// Add an annotation to this diagnostic.
|
||||
///
|
||||
/// Annotations for a diagnostic are optional, but if any are added,
|
||||
@@ -1057,13 +1019,6 @@ impl DiagnosticId {
|
||||
matches!(self, DiagnosticId::Lint(_))
|
||||
}
|
||||
|
||||
pub const fn as_lint(&self) -> Option<LintName> {
|
||||
match self {
|
||||
DiagnosticId::Lint(name) => Some(*name),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if this `DiagnosticId` represents a lint with the given name.
|
||||
pub fn is_lint_named(&self, name: &str) -> bool {
|
||||
matches!(self, DiagnosticId::Lint(self_name) if self_name == name)
|
||||
|
||||
@@ -14,7 +14,6 @@ use crate::diagnostic::{Span, UnifiedFile};
|
||||
use crate::file_revision::FileRevision;
|
||||
use crate::files::file_root::FileRoots;
|
||||
use crate::files::private::FileStatus;
|
||||
use crate::source::SourceText;
|
||||
use crate::system::{SystemPath, SystemPathBuf, SystemVirtualPath, SystemVirtualPathBuf};
|
||||
use crate::vendored::{VendoredPath, VendoredPathBuf};
|
||||
use crate::{Db, FxDashMap, vendored};
|
||||
@@ -324,17 +323,6 @@ pub struct File {
|
||||
/// the file has been deleted is to change the status to `Deleted`.
|
||||
#[default]
|
||||
status: FileStatus,
|
||||
|
||||
/// Overrides the result of [`source_text`](crate::source::source_text).
|
||||
///
|
||||
/// This is useful when running queries after modifying a file's content but
|
||||
/// before the content is written to disk. For example, to verify that the applied fixes
|
||||
/// didn't introduce any new errors.
|
||||
///
|
||||
/// The override gets automatically removed the next time the file changes.
|
||||
#[default]
|
||||
#[returns(ref)]
|
||||
pub source_text_override: Option<SourceText>,
|
||||
}
|
||||
|
||||
// The Salsa heap is tracked separately.
|
||||
@@ -456,28 +444,20 @@ impl File {
|
||||
_ => (FileStatus::NotFound, FileRevision::zero(), None),
|
||||
};
|
||||
|
||||
let mut clear_override = false;
|
||||
|
||||
if file.status(db) != status {
|
||||
tracing::debug!("Updating the status of `{}`", file.path(db));
|
||||
file.set_status(db).to(status);
|
||||
clear_override = true;
|
||||
}
|
||||
|
||||
if file.revision(db) != revision {
|
||||
tracing::debug!("Updating the revision of `{}`", file.path(db));
|
||||
file.set_revision(db).to(revision);
|
||||
clear_override = true;
|
||||
}
|
||||
|
||||
if file.permissions(db) != permission {
|
||||
tracing::debug!("Updating the permissions of `{}`", file.path(db));
|
||||
file.set_permissions(db).to(permission);
|
||||
}
|
||||
|
||||
if clear_override && file.source_text_override(db).is_some() {
|
||||
file.set_source_text_override(db).to(None);
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if the file exists.
|
||||
@@ -546,7 +526,7 @@ impl VirtualFile {
|
||||
}
|
||||
|
||||
/// Increments the revision of the underlying [`File`].
|
||||
pub fn sync(&self, db: &mut dyn Db) {
|
||||
fn sync(&self, db: &mut dyn Db) {
|
||||
let file = self.0;
|
||||
tracing::debug!("Updating the revision of `{}`", file.path(db));
|
||||
let current_revision = file.revision(db);
|
||||
|
||||
@@ -85,13 +85,6 @@ pub fn max_parallelism() -> NonZeroUsize {
|
||||
})
|
||||
}
|
||||
|
||||
// Use a reasonably large stack size to avoid running into stack overflows too easily. The
|
||||
// size was chosen in such a way as to still be able to handle large expressions involving
|
||||
// binary operators (x + x + … + x) both during the AST walk in semantic index building as
|
||||
// well as during type checking. Using this stack size, we can handle handle expressions
|
||||
// that are several times larger than the corresponding limits in existing type checkers.
|
||||
pub const STACK_SIZE: usize = 16 * 1024 * 1024;
|
||||
|
||||
/// Trait for types that can provide Rust documentation.
|
||||
///
|
||||
/// Use `derive(RustDoc)` to automatically implement this trait for types that have a static string documentation.
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
use std::borrow::Cow;
|
||||
use std::ops::Deref;
|
||||
use std::sync::Arc;
|
||||
|
||||
use ruff_diagnostics::SourceMap;
|
||||
use ruff_notebook::Notebook;
|
||||
use ruff_python_ast::PySourceType;
|
||||
use ruff_source_file::LineIndex;
|
||||
@@ -18,10 +16,6 @@ pub fn source_text(db: &dyn Db, file: File) -> SourceText {
|
||||
let _span = tracing::trace_span!("source_text", file = %path).entered();
|
||||
let mut read_error = None;
|
||||
|
||||
if let Some(source) = file.source_text_override(db) {
|
||||
return source.clone();
|
||||
}
|
||||
|
||||
let kind = if is_notebook(db.system(), path) {
|
||||
file.read_to_notebook(db)
|
||||
.unwrap_or_else(|error| {
|
||||
@@ -96,45 +90,6 @@ impl SourceText {
|
||||
pub fn read_error(&self) -> Option<&SourceTextError> {
|
||||
self.inner.read_error.as_ref()
|
||||
}
|
||||
|
||||
/// Returns a new instance for this file with the updated source text (Python code).
|
||||
///
|
||||
/// Uses the `source_map` to preserve the cell-boundaries.
|
||||
#[must_use]
|
||||
pub fn with_text(&self, new_text: String, source_map: &SourceMap) -> Self {
|
||||
let new_kind = match &self.inner.kind {
|
||||
SourceTextKind::Text(_) => SourceTextKind::Text(new_text),
|
||||
|
||||
SourceTextKind::Notebook { notebook } => {
|
||||
let mut new_notebook = notebook.as_ref().clone();
|
||||
new_notebook.update(source_map, new_text);
|
||||
SourceTextKind::Notebook {
|
||||
notebook: new_notebook.into(),
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Self {
|
||||
inner: Arc::new(SourceTextInner {
|
||||
kind: new_kind,
|
||||
read_error: self.inner.read_error.clone(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_bytes(&self) -> Cow<'_, [u8]> {
|
||||
match &self.inner.kind {
|
||||
SourceTextKind::Text(source) => Cow::Borrowed(source.as_bytes()),
|
||||
SourceTextKind::Notebook { notebook } => {
|
||||
let mut output: Vec<u8> = Vec::new();
|
||||
notebook
|
||||
.write(&mut output)
|
||||
.expect("writing to a Vec should never fail");
|
||||
|
||||
Cow::Owned(output)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for SourceText {
|
||||
@@ -162,13 +117,13 @@ impl std::fmt::Debug for SourceText {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Eq, PartialEq, get_size2::GetSize, Clone)]
|
||||
#[derive(Eq, PartialEq, get_size2::GetSize)]
|
||||
struct SourceTextInner {
|
||||
kind: SourceTextKind,
|
||||
read_error: Option<SourceTextError>,
|
||||
}
|
||||
|
||||
#[derive(Eq, PartialEq, get_size2::GetSize, Clone)]
|
||||
#[derive(Eq, PartialEq, get_size2::GetSize)]
|
||||
enum SourceTextKind {
|
||||
Text(String),
|
||||
Notebook {
|
||||
|
||||
@@ -271,12 +271,7 @@ pub trait WritableSystem: System {
|
||||
fn create_new_file(&self, path: &SystemPath) -> Result<()>;
|
||||
|
||||
/// Writes the given content to the file at the given path.
|
||||
fn write_file(&self, path: &SystemPath, content: &str) -> Result<()> {
|
||||
self.write_file_bytes(path, content.as_bytes())
|
||||
}
|
||||
|
||||
/// Writes the given content to the file at the given path.
|
||||
fn write_file_bytes(&self, path: &SystemPath, content: &[u8]) -> Result<()>;
|
||||
fn write_file(&self, path: &SystemPath, content: &str) -> Result<()>;
|
||||
|
||||
/// Creates a directory at `path` as well as any intermediate directories.
|
||||
fn create_directory_all(&self, path: &SystemPath) -> Result<()>;
|
||||
@@ -316,8 +311,6 @@ pub trait WritableSystem: System {
|
||||
|
||||
Ok(Some(cache_path))
|
||||
}
|
||||
|
||||
fn dyn_clone(&self) -> Box<dyn WritableSystem>;
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
|
||||
@@ -122,9 +122,7 @@ impl MemoryFileSystem {
|
||||
let entry = by_path.get(&normalized).ok_or_else(not_found)?;
|
||||
|
||||
match entry {
|
||||
Entry::File(file) => {
|
||||
String::from_utf8(file.content.to_vec()).map_err(|_| invalid_utf8())
|
||||
}
|
||||
Entry::File(file) => Ok(file.content.clone()),
|
||||
Entry::Directory(_) => Err(is_a_directory()),
|
||||
}
|
||||
}
|
||||
@@ -141,7 +139,7 @@ impl MemoryFileSystem {
|
||||
.get(&path.as_ref().to_path_buf())
|
||||
.ok_or_else(not_found)?;
|
||||
|
||||
String::from_utf8(file.content.to_vec()).map_err(|_| invalid_utf8())
|
||||
Ok(file.content.clone())
|
||||
}
|
||||
|
||||
pub fn exists(&self, path: &SystemPath) -> bool {
|
||||
@@ -163,7 +161,7 @@ impl MemoryFileSystem {
|
||||
match by_path.entry(normalized) {
|
||||
btree_map::Entry::Vacant(entry) => {
|
||||
entry.insert(Entry::File(File {
|
||||
content: Box::default(),
|
||||
content: String::new(),
|
||||
last_modified: file_time_now(),
|
||||
}));
|
||||
|
||||
@@ -179,17 +177,13 @@ impl MemoryFileSystem {
|
||||
/// Stores a new file in the file system.
|
||||
///
|
||||
/// The operation overrides the content for an existing file with the same normalized `path`.
|
||||
pub fn write_file(
|
||||
&self,
|
||||
path: impl AsRef<SystemPath>,
|
||||
content: impl AsRef<[u8]>,
|
||||
) -> Result<()> {
|
||||
pub fn write_file(&self, path: impl AsRef<SystemPath>, content: impl ToString) -> Result<()> {
|
||||
let mut by_path = self.inner.by_path.write().unwrap();
|
||||
|
||||
let normalized = self.normalize_path(path.as_ref());
|
||||
|
||||
let file = get_or_create_file(&mut by_path, &normalized)?;
|
||||
file.content = content.as_ref().to_vec().into_boxed_slice();
|
||||
file.content = content.to_string();
|
||||
file.last_modified = file_time_now();
|
||||
|
||||
Ok(())
|
||||
@@ -220,7 +214,7 @@ impl MemoryFileSystem {
|
||||
pub fn write_file_all(
|
||||
&self,
|
||||
path: impl AsRef<SystemPath>,
|
||||
content: impl AsRef<[u8]>,
|
||||
content: impl ToString,
|
||||
) -> Result<()> {
|
||||
let path = path.as_ref();
|
||||
|
||||
@@ -234,24 +228,19 @@ impl MemoryFileSystem {
|
||||
/// Stores a new virtual file in the file system.
|
||||
///
|
||||
/// The operation overrides the content for an existing virtual file with the same `path`.
|
||||
pub fn write_virtual_file(
|
||||
&self,
|
||||
path: impl AsRef<SystemVirtualPath>,
|
||||
content: impl AsRef<[u8]>,
|
||||
) {
|
||||
pub fn write_virtual_file(&self, path: impl AsRef<SystemVirtualPath>, content: impl ToString) {
|
||||
let path = path.as_ref();
|
||||
let mut virtual_files = self.inner.virtual_files.write().unwrap();
|
||||
let content = content.as_ref().to_vec().into_boxed_slice();
|
||||
|
||||
match virtual_files.entry(path.to_path_buf()) {
|
||||
std::collections::hash_map::Entry::Vacant(entry) => {
|
||||
entry.insert(File {
|
||||
content,
|
||||
content: content.to_string(),
|
||||
last_modified: file_time_now(),
|
||||
});
|
||||
}
|
||||
std::collections::hash_map::Entry::Occupied(mut entry) => {
|
||||
entry.get_mut().content = content;
|
||||
entry.get_mut().content = content.to_string();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -479,7 +468,7 @@ impl Entry {
|
||||
|
||||
#[derive(Debug)]
|
||||
struct File {
|
||||
content: Box<[u8]>,
|
||||
content: String,
|
||||
last_modified: FileTime,
|
||||
}
|
||||
|
||||
@@ -508,13 +497,6 @@ fn directory_not_empty() -> std::io::Error {
|
||||
std::io::Error::other("directory not empty")
|
||||
}
|
||||
|
||||
fn invalid_utf8() -> std::io::Error {
|
||||
std::io::Error::new(
|
||||
std::io::ErrorKind::InvalidData,
|
||||
"stream did not contain valid UTF-8",
|
||||
)
|
||||
}
|
||||
|
||||
fn create_dir_all(
|
||||
paths: &mut RwLockWriteGuard<BTreeMap<Utf8PathBuf, Entry>>,
|
||||
normalized: &Utf8Path,
|
||||
@@ -551,7 +533,7 @@ fn get_or_create_file<'a>(
|
||||
|
||||
let entry = paths.entry(normalized.to_path_buf()).or_insert_with(|| {
|
||||
Entry::File(File {
|
||||
content: Box::default(),
|
||||
content: String::new(),
|
||||
last_modified: file_time_now(),
|
||||
})
|
||||
});
|
||||
@@ -862,7 +844,7 @@ mod tests {
|
||||
let fs = with_files(["c.py"]);
|
||||
|
||||
let error = fs
|
||||
.write_file(SystemPath::new("a/b.py"), "content")
|
||||
.write_file(SystemPath::new("a/b.py"), "content".to_string())
|
||||
.unwrap_err();
|
||||
|
||||
assert_eq!(error.kind(), ErrorKind::NotFound);
|
||||
@@ -873,7 +855,7 @@ mod tests {
|
||||
let fs = with_files(["a/b.py"]);
|
||||
|
||||
let error = fs
|
||||
.write_file_all(SystemPath::new("a/b.py/c"), "content")
|
||||
.write_file_all(SystemPath::new("a/b.py/c"), "content".to_string())
|
||||
.unwrap_err();
|
||||
|
||||
assert_eq!(error.kind(), ErrorKind::Other);
|
||||
@@ -896,7 +878,7 @@ mod tests {
|
||||
let fs = MemoryFileSystem::new();
|
||||
let path = SystemPath::new("a.py");
|
||||
|
||||
fs.write_file_all(path, "Test content")?;
|
||||
fs.write_file_all(path, "Test content".to_string())?;
|
||||
|
||||
assert_eq!(fs.read_to_string(path)?, "Test content");
|
||||
|
||||
@@ -933,7 +915,9 @@ mod tests {
|
||||
|
||||
fs.create_directory_all("a")?;
|
||||
|
||||
let error = fs.write_file(SystemPath::new("a"), "content").unwrap_err();
|
||||
let error = fs
|
||||
.write_file(SystemPath::new("a"), "content".to_string())
|
||||
.unwrap_err();
|
||||
|
||||
assert_eq!(error.kind(), ErrorKind::Other);
|
||||
|
||||
|
||||
@@ -361,17 +361,13 @@ impl WritableSystem for OsSystem {
|
||||
std::fs::File::create_new(path).map(drop)
|
||||
}
|
||||
|
||||
fn write_file_bytes(&self, path: &SystemPath, content: &[u8]) -> Result<()> {
|
||||
fn write_file(&self, path: &SystemPath, content: &str) -> Result<()> {
|
||||
std::fs::write(path.as_std_path(), content)
|
||||
}
|
||||
|
||||
fn create_directory_all(&self, path: &SystemPath) -> Result<()> {
|
||||
std::fs::create_dir_all(path.as_std_path())
|
||||
}
|
||||
|
||||
fn dyn_clone(&self) -> Box<dyn WritableSystem> {
|
||||
Box::new(self.clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for OsSystem {
|
||||
|
||||
@@ -205,17 +205,13 @@ impl WritableSystem for TestSystem {
|
||||
self.system().create_new_file(path)
|
||||
}
|
||||
|
||||
fn write_file_bytes(&self, path: &SystemPath, content: &[u8]) -> Result<()> {
|
||||
self.system().write_file_bytes(path, content)
|
||||
fn write_file(&self, path: &SystemPath, content: &str) -> Result<()> {
|
||||
self.system().write_file(path, content)
|
||||
}
|
||||
|
||||
fn create_directory_all(&self, path: &SystemPath) -> Result<()> {
|
||||
self.system().create_directory_all(path)
|
||||
}
|
||||
|
||||
fn dyn_clone(&self) -> Box<dyn WritableSystem> {
|
||||
Box::new(self.clone())
|
||||
}
|
||||
}
|
||||
|
||||
/// Extension trait for databases that use a [`WritableSystem`].
|
||||
@@ -287,11 +283,7 @@ pub trait DbWithTestSystem: Db + Sized {
|
||||
///
|
||||
/// ## Panics
|
||||
/// If the db isn't using the [`InMemorySystem`].
|
||||
fn write_virtual_file(
|
||||
&mut self,
|
||||
path: impl AsRef<SystemVirtualPath>,
|
||||
content: impl AsRef<[u8]>,
|
||||
) {
|
||||
fn write_virtual_file(&mut self, path: impl AsRef<SystemVirtualPath>, content: impl ToString) {
|
||||
let path = path.as_ref();
|
||||
self.test_system()
|
||||
.memory_file_system()
|
||||
@@ -330,23 +322,23 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Default, Debug)]
|
||||
#[derive(Default, Debug)]
|
||||
pub struct InMemorySystem {
|
||||
user_config_directory: Arc<Mutex<Option<SystemPathBuf>>>,
|
||||
user_config_directory: Mutex<Option<SystemPathBuf>>,
|
||||
memory_fs: MemoryFileSystem,
|
||||
}
|
||||
|
||||
impl InMemorySystem {
|
||||
pub fn new(cwd: SystemPathBuf) -> Self {
|
||||
Self {
|
||||
user_config_directory: Mutex::new(None).into(),
|
||||
user_config_directory: Mutex::new(None),
|
||||
memory_fs: MemoryFileSystem::with_current_directory(cwd),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_memory_fs(memory_fs: MemoryFileSystem) -> Self {
|
||||
Self {
|
||||
user_config_directory: Mutex::new(None).into(),
|
||||
user_config_directory: Mutex::new(None),
|
||||
memory_fs,
|
||||
}
|
||||
}
|
||||
@@ -448,7 +440,10 @@ impl System for InMemorySystem {
|
||||
}
|
||||
|
||||
fn dyn_clone(&self) -> Box<dyn System> {
|
||||
Box::new(self.clone())
|
||||
Box::new(Self {
|
||||
user_config_directory: Mutex::new(self.user_config_directory.lock().unwrap().clone()),
|
||||
memory_fs: self.memory_fs.clone(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -457,15 +452,11 @@ impl WritableSystem for InMemorySystem {
|
||||
self.memory_fs.create_new_file(path)
|
||||
}
|
||||
|
||||
fn write_file_bytes(&self, path: &SystemPath, content: &[u8]) -> Result<()> {
|
||||
fn write_file(&self, path: &SystemPath, content: &str) -> Result<()> {
|
||||
self.memory_fs.write_file(path, content)
|
||||
}
|
||||
|
||||
fn create_directory_all(&self, path: &SystemPath) -> Result<()> {
|
||||
self.memory_fs.create_directory_all(path)
|
||||
}
|
||||
|
||||
fn dyn_clone(&self) -> Box<dyn WritableSystem> {
|
||||
Box::new(self.clone())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "ruff_linter"
|
||||
version = "0.14.11"
|
||||
version = "0.14.10"
|
||||
publish = false
|
||||
authors = { workspace = true }
|
||||
edition = { workspace = true }
|
||||
|
||||
@@ -26,7 +26,6 @@ use crate::doc_lines::{doc_lines_from_ast, doc_lines_from_tokens};
|
||||
use crate::fix::{FixResult, fix_file};
|
||||
use crate::noqa::add_noqa;
|
||||
use crate::package::PackageRoot;
|
||||
use crate::preview::is_py315_support_enabled;
|
||||
use crate::registry::Rule;
|
||||
#[cfg(any(feature = "test-rules", test))]
|
||||
use crate::rules::ruff::rules::test_rules::{self, TEST_RULES, TestRule};
|
||||
@@ -34,7 +33,7 @@ use crate::settings::types::UnsafeFixes;
|
||||
use crate::settings::{LinterSettings, TargetVersion, flags};
|
||||
use crate::source_kind::SourceKind;
|
||||
use crate::suppression::Suppressions;
|
||||
use crate::{Locator, directives, fs, warn_user_once};
|
||||
use crate::{Locator, directives, fs};
|
||||
|
||||
pub(crate) mod float;
|
||||
|
||||
@@ -451,14 +450,6 @@ pub fn lint_only(
|
||||
) -> LinterResult {
|
||||
let target_version = settings.resolve_target_version(path);
|
||||
|
||||
if matches!(target_version.linter_version(), PythonVersion::PY315)
|
||||
&& !is_py315_support_enabled(settings)
|
||||
{
|
||||
warn_user_once!(
|
||||
"Support for Python 3.15 is under development and may be unstable. Enable `preview` to remove this warning."
|
||||
);
|
||||
}
|
||||
|
||||
let parsed = source.into_parsed(source_kind, source_type, target_version.parser_version());
|
||||
|
||||
// Map row and column locations to byte slices (lazily).
|
||||
@@ -564,14 +555,6 @@ pub fn lint_fix<'a>(
|
||||
|
||||
let target_version = settings.resolve_target_version(path);
|
||||
|
||||
if matches!(target_version.linter_version(), PythonVersion::PY315)
|
||||
&& !is_py315_support_enabled(settings)
|
||||
{
|
||||
warn_user_once!(
|
||||
"Support for Python 3.15 is under development and may be unstable. Enable `preview` to remove this warning."
|
||||
);
|
||||
}
|
||||
|
||||
// Continuously fix until the source code stabilizes.
|
||||
loop {
|
||||
// Parse once.
|
||||
|
||||
@@ -296,8 +296,3 @@ pub(crate) const fn is_s310_resolve_string_literal_bindings_enabled(
|
||||
pub(crate) const fn is_range_suppressions_enabled(settings: &LinterSettings) -> bool {
|
||||
settings.preview.is_enabled()
|
||||
}
|
||||
|
||||
// https://github.com/astral-sh/ruff/pull/22419
|
||||
pub(crate) const fn is_py315_support_enabled(settings: &LinterSettings) -> bool {
|
||||
settings.preview.is_enabled()
|
||||
}
|
||||
|
||||
@@ -36,16 +36,13 @@ use crate::{Fix, FixAvailability, Violation};
|
||||
/// ```python
|
||||
/// import logging
|
||||
///
|
||||
/// logging.basicConfig(level=logging.INFO)
|
||||
/// logger = logging.getLogger(__name__)
|
||||
///
|
||||
///
|
||||
/// def sum_less_than_four(a, b):
|
||||
/// logger.debug("Calling sum_less_than_four")
|
||||
/// return a + b < 4
|
||||
///
|
||||
///
|
||||
/// if __name__ == "__main__":
|
||||
/// logging.basicConfig(level=logging.INFO)
|
||||
/// ```
|
||||
///
|
||||
/// ## Fix safety
|
||||
|
||||
@@ -5,7 +5,7 @@ use ruff_text_size::Ranged;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::fix::edits::add_argument;
|
||||
use crate::{Fix, FixAvailability, Violation};
|
||||
use crate::{AlwaysFixableViolation, Applicability, Fix};
|
||||
|
||||
/// ## What it does
|
||||
/// Checks for uses of `subprocess.run` without an explicit `check` argument.
|
||||
@@ -39,12 +39,9 @@ use crate::{Fix, FixAvailability, Violation};
|
||||
/// ```
|
||||
///
|
||||
/// ## Fix safety
|
||||
///
|
||||
/// This rule's fix is marked as display-only because it's not clear whether the
|
||||
/// potential exception was meant to be ignored by setting `check=False` or if
|
||||
/// the author simply forgot to include `check=True`. The fix adds
|
||||
/// `check=False`, making the existing behavior explicit but possibly masking
|
||||
/// the original intention.
|
||||
/// This rule's fix is marked as unsafe for function calls that contain
|
||||
/// `**kwargs`, as adding a `check` keyword argument to such a call may lead
|
||||
/// to a duplicate keyword argument error.
|
||||
///
|
||||
/// ## References
|
||||
/// - [Python documentation: `subprocess.run`](https://docs.python.org/3/library/subprocess.html#subprocess.run)
|
||||
@@ -52,18 +49,14 @@ use crate::{Fix, FixAvailability, Violation};
|
||||
#[violation_metadata(stable_since = "v0.0.285")]
|
||||
pub(crate) struct SubprocessRunWithoutCheck;
|
||||
|
||||
impl Violation for SubprocessRunWithoutCheck {
|
||||
// The fix is always set on the diagnostic, but display-only fixes aren't
|
||||
// considered "fixable" in the tests.
|
||||
const FIX_AVAILABILITY: FixAvailability = FixAvailability::Sometimes;
|
||||
|
||||
impl AlwaysFixableViolation for SubprocessRunWithoutCheck {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
"`subprocess.run` without explicit `check` argument".to_string()
|
||||
}
|
||||
|
||||
fn fix_title(&self) -> Option<String> {
|
||||
Some("Add explicit `check=False`".to_string())
|
||||
fn fix_title(&self) -> String {
|
||||
"Add explicit `check=False`".to_string()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,11 +74,20 @@ pub(crate) fn subprocess_run_without_check(checker: &Checker, call: &ast::ExprCa
|
||||
if call.arguments.find_keyword("check").is_none() {
|
||||
let mut diagnostic =
|
||||
checker.report_diagnostic(SubprocessRunWithoutCheck, call.func.range());
|
||||
diagnostic.set_fix(Fix::display_only_edit(add_argument(
|
||||
"check=False",
|
||||
&call.arguments,
|
||||
checker.tokens(),
|
||||
)));
|
||||
diagnostic.set_fix(Fix::applicable_edit(
|
||||
add_argument("check=False", &call.arguments, checker.tokens()),
|
||||
// If the function call contains `**kwargs`, mark the fix as unsafe.
|
||||
if call
|
||||
.arguments
|
||||
.keywords
|
||||
.iter()
|
||||
.any(|keyword| keyword.arg.is_none())
|
||||
{
|
||||
Applicability::Unsafe
|
||||
} else {
|
||||
Applicability::Safe
|
||||
},
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,6 @@ help: Add explicit `check=False`
|
||||
5 | subprocess.run("ls", shell=True)
|
||||
6 | subprocess.run(
|
||||
7 | ["ls"],
|
||||
note: This is a display-only fix and is likely to be incorrect
|
||||
|
||||
PLW1510 [*] `subprocess.run` without explicit `check` argument
|
||||
--> subprocess_run_without_check.py:5:1
|
||||
@@ -40,7 +39,6 @@ help: Add explicit `check=False`
|
||||
6 | subprocess.run(
|
||||
7 | ["ls"],
|
||||
8 | shell=False,
|
||||
note: This is a display-only fix and is likely to be incorrect
|
||||
|
||||
PLW1510 [*] `subprocess.run` without explicit `check` argument
|
||||
--> subprocess_run_without_check.py:6:1
|
||||
@@ -61,7 +59,6 @@ help: Add explicit `check=False`
|
||||
9 | )
|
||||
10 | subprocess.run(["ls"], **kwargs)
|
||||
11 |
|
||||
note: This is a display-only fix and is likely to be incorrect
|
||||
|
||||
PLW1510 [*] `subprocess.run` without explicit `check` argument
|
||||
--> subprocess_run_without_check.py:10:1
|
||||
@@ -82,4 +79,4 @@ help: Add explicit `check=False`
|
||||
11 |
|
||||
12 | # Non-errors.
|
||||
13 | subprocess.run("ls", check=True)
|
||||
note: This is a display-only fix and is likely to be incorrect
|
||||
note: This is an unsafe fix and may change runtime behavior
|
||||
|
||||
@@ -52,7 +52,6 @@ impl InvalidRuleCodeKind {
|
||||
pub(crate) struct InvalidRuleCode {
|
||||
pub(crate) rule_code: String,
|
||||
pub(crate) kind: InvalidRuleCodeKind,
|
||||
pub(crate) whole_comment: bool,
|
||||
}
|
||||
|
||||
impl AlwaysFixableViolation for InvalidRuleCode {
|
||||
@@ -66,11 +65,7 @@ impl AlwaysFixableViolation for InvalidRuleCode {
|
||||
}
|
||||
|
||||
fn fix_title(&self) -> String {
|
||||
if self.whole_comment {
|
||||
format!("Remove the {} comment", self.kind.as_str())
|
||||
} else {
|
||||
format!("Remove the rule code `{}`", self.rule_code)
|
||||
}
|
||||
"Remove the rule code".to_string()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -127,7 +122,6 @@ fn all_codes_invalid_diagnostic(
|
||||
.collect::<Vec<_>>()
|
||||
.join(", "),
|
||||
kind: InvalidRuleCodeKind::Noqa,
|
||||
whole_comment: true,
|
||||
},
|
||||
directive.range(),
|
||||
)
|
||||
@@ -145,7 +139,6 @@ fn some_codes_are_invalid_diagnostic(
|
||||
InvalidRuleCode {
|
||||
rule_code: invalid_code.to_string(),
|
||||
kind: InvalidRuleCodeKind::Noqa,
|
||||
whole_comment: false,
|
||||
},
|
||||
invalid_code.range(),
|
||||
)
|
||||
|
||||
@@ -52,25 +52,6 @@ impl UnusedNOQAKind {
|
||||
/// foo.bar()
|
||||
/// ```
|
||||
///
|
||||
/// ## Conflict with other linters
|
||||
/// When using `RUF100` with the `--fix` option, Ruff may remove trailing comments
|
||||
/// that follow a `# noqa` directive on the same line, as it interprets the
|
||||
/// remainder of the line as a description for the suppression.
|
||||
///
|
||||
/// To prevent Ruff from removing suppressions for other tools (like `pylint`
|
||||
/// or `mypy`), separate them with a second `#` character:
|
||||
///
|
||||
/// ```python
|
||||
/// # Bad: Ruff --fix will remove the pylint comment
|
||||
/// def visit_ImportFrom(self, node): # noqa: N802, pylint: disable=invalid-name
|
||||
/// pass
|
||||
///
|
||||
///
|
||||
/// # Good: Ruff will preserve the pylint comment
|
||||
/// def visit_ImportFrom(self, node): # noqa: N802 # pylint: disable=invalid-name
|
||||
/// pass
|
||||
/// ```
|
||||
///
|
||||
/// ## Options
|
||||
/// - `lint.external`
|
||||
///
|
||||
|
||||
@@ -10,7 +10,7 @@ RUF102 [*] Invalid rule code in `# noqa`: INVALID123
|
||||
3 | # External code
|
||||
4 | import re # noqa: V123
|
||||
|
|
||||
help: Remove the `# noqa` comment
|
||||
help: Remove the rule code
|
||||
1 | # Invalid code
|
||||
- import os # noqa: INVALID123
|
||||
2 + import os
|
||||
@@ -28,7 +28,7 @@ RUF102 [*] Invalid rule code in `# noqa`: V123
|
||||
5 | # Valid noqa
|
||||
6 | import sys # noqa: E402
|
||||
|
|
||||
help: Remove the `# noqa` comment
|
||||
help: Remove the rule code
|
||||
1 | # Invalid code
|
||||
2 | import os # noqa: INVALID123
|
||||
3 | # External code
|
||||
@@ -48,7 +48,7 @@ RUF102 [*] Invalid rule code in `# noqa`: INVALID456
|
||||
8 | from itertools import product # Preceeding comment # noqa: INVALID789
|
||||
9 | # Succeeding comment
|
||||
|
|
||||
help: Remove the rule code `INVALID456`
|
||||
help: Remove the rule code
|
||||
4 | import re # noqa: V123
|
||||
5 | # Valid noqa
|
||||
6 | import sys # noqa: E402
|
||||
@@ -68,7 +68,7 @@ RUF102 [*] Invalid rule code in `# noqa`: INVALID789
|
||||
9 | # Succeeding comment
|
||||
10 | import math # noqa: INVALID000 # Succeeding comment
|
||||
|
|
||||
help: Remove the `# noqa` comment
|
||||
help: Remove the rule code
|
||||
5 | # Valid noqa
|
||||
6 | import sys # noqa: E402
|
||||
7 | from functools import cache # Preceeding comment # noqa: F401, INVALID456
|
||||
@@ -88,7 +88,7 @@ RUF102 [*] Invalid rule code in `# noqa`: INVALID000
|
||||
11 | # Mixed valid and invalid
|
||||
12 | from typing import List # noqa: F401, INVALID123
|
||||
|
|
||||
help: Remove the `# noqa` comment
|
||||
help: Remove the rule code
|
||||
7 | from functools import cache # Preceeding comment # noqa: F401, INVALID456
|
||||
8 | from itertools import product # Preceeding comment # noqa: INVALID789
|
||||
9 | # Succeeding comment
|
||||
@@ -108,7 +108,7 @@ RUF102 [*] Invalid rule code in `# noqa`: INVALID123
|
||||
13 | # Test for multiple invalid
|
||||
14 | from collections import defaultdict # noqa: INVALID100, INVALID200, F401
|
||||
|
|
||||
help: Remove the rule code `INVALID123`
|
||||
help: Remove the rule code
|
||||
9 | # Succeeding comment
|
||||
10 | import math # noqa: INVALID000 # Succeeding comment
|
||||
11 | # Mixed valid and invalid
|
||||
@@ -128,7 +128,7 @@ RUF102 [*] Invalid rule code in `# noqa`: INVALID100
|
||||
15 | # Test for preserving valid codes when fixing
|
||||
16 | from itertools import chain # noqa: E402, INVALID300, F401
|
||||
|
|
||||
help: Remove the rule code `INVALID100`
|
||||
help: Remove the rule code
|
||||
11 | # Mixed valid and invalid
|
||||
12 | from typing import List # noqa: F401, INVALID123
|
||||
13 | # Test for multiple invalid
|
||||
@@ -148,7 +148,7 @@ RUF102 [*] Invalid rule code in `# noqa`: INVALID200
|
||||
15 | # Test for preserving valid codes when fixing
|
||||
16 | from itertools import chain # noqa: E402, INVALID300, F401
|
||||
|
|
||||
help: Remove the rule code `INVALID200`
|
||||
help: Remove the rule code
|
||||
11 | # Mixed valid and invalid
|
||||
12 | from typing import List # noqa: F401, INVALID123
|
||||
13 | # Test for multiple invalid
|
||||
@@ -168,7 +168,7 @@ RUF102 [*] Invalid rule code in `# noqa`: INVALID300
|
||||
17 | # Test for mixed code types
|
||||
18 | import json # noqa: E402, INVALID400, V100
|
||||
|
|
||||
help: Remove the rule code `INVALID300`
|
||||
help: Remove the rule code
|
||||
13 | # Test for multiple invalid
|
||||
14 | from collections import defaultdict # noqa: INVALID100, INVALID200, F401
|
||||
15 | # Test for preserving valid codes when fixing
|
||||
@@ -188,7 +188,7 @@ RUF102 [*] Invalid rule code in `# noqa`: INVALID400
|
||||
19 | # Test for rule redirects
|
||||
20 | import pandas as pd # noqa: TCH002
|
||||
|
|
||||
help: Remove the rule code `INVALID400`
|
||||
help: Remove the rule code
|
||||
15 | # Test for preserving valid codes when fixing
|
||||
16 | from itertools import chain # noqa: E402, INVALID300, F401
|
||||
17 | # Test for mixed code types
|
||||
@@ -207,7 +207,7 @@ RUF102 [*] Invalid rule code in `# noqa`: V100
|
||||
19 | # Test for rule redirects
|
||||
20 | import pandas as pd # noqa: TCH002
|
||||
|
|
||||
help: Remove the rule code `V100`
|
||||
help: Remove the rule code
|
||||
15 | # Test for preserving valid codes when fixing
|
||||
16 | from itertools import chain # noqa: E402, INVALID300, F401
|
||||
17 | # Test for mixed code types
|
||||
|
||||
@@ -10,7 +10,7 @@ RUF102 [*] Invalid rule code in `# noqa`: INVALID123
|
||||
3 | # External code
|
||||
4 | import re # noqa: V123
|
||||
|
|
||||
help: Remove the `# noqa` comment
|
||||
help: Remove the rule code
|
||||
1 | # Invalid code
|
||||
- import os # noqa: INVALID123
|
||||
2 + import os
|
||||
@@ -28,7 +28,7 @@ RUF102 [*] Invalid rule code in `# noqa`: INVALID456
|
||||
8 | from itertools import product # Preceeding comment # noqa: INVALID789
|
||||
9 | # Succeeding comment
|
||||
|
|
||||
help: Remove the rule code `INVALID456`
|
||||
help: Remove the rule code
|
||||
4 | import re # noqa: V123
|
||||
5 | # Valid noqa
|
||||
6 | import sys # noqa: E402
|
||||
@@ -48,7 +48,7 @@ RUF102 [*] Invalid rule code in `# noqa`: INVALID789
|
||||
9 | # Succeeding comment
|
||||
10 | import math # noqa: INVALID000 # Succeeding comment
|
||||
|
|
||||
help: Remove the `# noqa` comment
|
||||
help: Remove the rule code
|
||||
5 | # Valid noqa
|
||||
6 | import sys # noqa: E402
|
||||
7 | from functools import cache # Preceeding comment # noqa: F401, INVALID456
|
||||
@@ -68,7 +68,7 @@ RUF102 [*] Invalid rule code in `# noqa`: INVALID000
|
||||
11 | # Mixed valid and invalid
|
||||
12 | from typing import List # noqa: F401, INVALID123
|
||||
|
|
||||
help: Remove the `# noqa` comment
|
||||
help: Remove the rule code
|
||||
7 | from functools import cache # Preceeding comment # noqa: F401, INVALID456
|
||||
8 | from itertools import product # Preceeding comment # noqa: INVALID789
|
||||
9 | # Succeeding comment
|
||||
@@ -88,7 +88,7 @@ RUF102 [*] Invalid rule code in `# noqa`: INVALID123
|
||||
13 | # Test for multiple invalid
|
||||
14 | from collections import defaultdict # noqa: INVALID100, INVALID200, F401
|
||||
|
|
||||
help: Remove the rule code `INVALID123`
|
||||
help: Remove the rule code
|
||||
9 | # Succeeding comment
|
||||
10 | import math # noqa: INVALID000 # Succeeding comment
|
||||
11 | # Mixed valid and invalid
|
||||
@@ -108,7 +108,7 @@ RUF102 [*] Invalid rule code in `# noqa`: INVALID100
|
||||
15 | # Test for preserving valid codes when fixing
|
||||
16 | from itertools import chain # noqa: E402, INVALID300, F401
|
||||
|
|
||||
help: Remove the rule code `INVALID100`
|
||||
help: Remove the rule code
|
||||
11 | # Mixed valid and invalid
|
||||
12 | from typing import List # noqa: F401, INVALID123
|
||||
13 | # Test for multiple invalid
|
||||
@@ -128,7 +128,7 @@ RUF102 [*] Invalid rule code in `# noqa`: INVALID200
|
||||
15 | # Test for preserving valid codes when fixing
|
||||
16 | from itertools import chain # noqa: E402, INVALID300, F401
|
||||
|
|
||||
help: Remove the rule code `INVALID200`
|
||||
help: Remove the rule code
|
||||
11 | # Mixed valid and invalid
|
||||
12 | from typing import List # noqa: F401, INVALID123
|
||||
13 | # Test for multiple invalid
|
||||
@@ -148,7 +148,7 @@ RUF102 [*] Invalid rule code in `# noqa`: INVALID300
|
||||
17 | # Test for mixed code types
|
||||
18 | import json # noqa: E402, INVALID400, V100
|
||||
|
|
||||
help: Remove the rule code `INVALID300`
|
||||
help: Remove the rule code
|
||||
13 | # Test for multiple invalid
|
||||
14 | from collections import defaultdict # noqa: INVALID100, INVALID200, F401
|
||||
15 | # Test for preserving valid codes when fixing
|
||||
@@ -168,7 +168,7 @@ RUF102 [*] Invalid rule code in `# noqa`: INVALID400
|
||||
19 | # Test for rule redirects
|
||||
20 | import pandas as pd # noqa: TCH002
|
||||
|
|
||||
help: Remove the rule code `INVALID400`
|
||||
help: Remove the rule code
|
||||
15 | # Test for preserving valid codes when fixing
|
||||
16 | from itertools import chain # noqa: E402, INVALID300, F401
|
||||
17 | # Test for mixed code types
|
||||
|
||||
@@ -7,7 +7,7 @@ source: crates/ruff_linter/src/rules/ruff/mod.rs
|
||||
|
||||
--- Summary ---
|
||||
Removed: 15
|
||||
Added: 20
|
||||
Added: 23
|
||||
|
||||
--- Removed ---
|
||||
E741 Ambiguous variable name: `I`
|
||||
@@ -301,7 +301,6 @@ RUF100 [*] Unused suppression (non-enabled: `E501`)
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
47 | I = 1
|
||||
48 | # ruff: enable[E501]
|
||||
| --------------------
|
||||
|
|
||||
help: Remove unused suppression
|
||||
43 | def f():
|
||||
@@ -309,10 +308,26 @@ help: Remove unused suppression
|
||||
45 | # logged to user
|
||||
- # ruff: disable[E501]
|
||||
46 | I = 1
|
||||
- # ruff: enable[E501]
|
||||
47 |
|
||||
47 | # ruff: enable[E501]
|
||||
48 |
|
||||
49 | def f():
|
||||
|
||||
|
||||
RUF100 [*] Unused suppression (non-enabled: `E501`)
|
||||
--> suppressions.py:48:5
|
||||
|
|
||||
46 | # ruff: disable[E501]
|
||||
47 | I = 1
|
||||
48 | # ruff: enable[E501]
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: Remove unused suppression
|
||||
45 | # logged to user
|
||||
46 | # ruff: disable[E501]
|
||||
47 | I = 1
|
||||
- # ruff: enable[E501]
|
||||
48 |
|
||||
49 |
|
||||
50 | def f():
|
||||
|
||||
|
||||
RUF100 [*] Unused `noqa` directive (unused: `E741`, `F841`)
|
||||
@@ -548,11 +563,8 @@ RUF102 [*] Invalid rule code in suppression: YF829
|
||||
| ^^^^^
|
||||
94 | # ruff: disable[F841, RQW320]
|
||||
95 | value = 0
|
||||
96 | # ruff: enable[F841, RQW320]
|
||||
97 | # ruff: enable[YF829]
|
||||
| -----
|
||||
|
|
||||
help: Remove the suppression comment
|
||||
help: Remove the rule code
|
||||
90 |
|
||||
91 | def f():
|
||||
92 | # Unknown rule codes
|
||||
@@ -560,10 +572,6 @@ help: Remove the suppression comment
|
||||
93 | # ruff: disable[F841, RQW320]
|
||||
94 | value = 0
|
||||
95 | # ruff: enable[F841, RQW320]
|
||||
- # ruff: enable[YF829]
|
||||
96 |
|
||||
97 |
|
||||
98 | def f():
|
||||
|
||||
|
||||
RUF102 [*] Invalid rule code in suppression: RQW320
|
||||
@@ -575,15 +583,30 @@ RUF102 [*] Invalid rule code in suppression: RQW320
|
||||
| ^^^^^^
|
||||
95 | value = 0
|
||||
96 | # ruff: enable[F841, RQW320]
|
||||
| ------
|
||||
97 | # ruff: enable[YF829]
|
||||
|
|
||||
help: Remove the rule code `RQW320`
|
||||
help: Remove the rule code
|
||||
91 | def f():
|
||||
92 | # Unknown rule codes
|
||||
93 | # ruff: disable[YF829]
|
||||
- # ruff: disable[F841, RQW320]
|
||||
94 + # ruff: disable[F841]
|
||||
95 | value = 0
|
||||
96 | # ruff: enable[F841, RQW320]
|
||||
97 | # ruff: enable[YF829]
|
||||
|
||||
|
||||
RUF102 [*] Invalid rule code in suppression: RQW320
|
||||
--> suppressions.py:96:26
|
||||
|
|
||||
94 | # ruff: disable[F841, RQW320]
|
||||
95 | value = 0
|
||||
96 | # ruff: enable[F841, RQW320]
|
||||
| ^^^^^^
|
||||
97 | # ruff: enable[YF829]
|
||||
|
|
||||
help: Remove the rule code
|
||||
93 | # ruff: disable[YF829]
|
||||
94 | # ruff: disable[F841, RQW320]
|
||||
95 | value = 0
|
||||
- # ruff: enable[F841, RQW320]
|
||||
96 + # ruff: enable[F841]
|
||||
@@ -592,6 +615,24 @@ help: Remove the rule code `RQW320`
|
||||
99 |
|
||||
|
||||
|
||||
RUF102 [*] Invalid rule code in suppression: YF829
|
||||
--> suppressions.py:97:20
|
||||
|
|
||||
95 | value = 0
|
||||
96 | # ruff: enable[F841, RQW320]
|
||||
97 | # ruff: enable[YF829]
|
||||
| ^^^^^
|
||||
|
|
||||
help: Remove the rule code
|
||||
94 | # ruff: disable[F841, RQW320]
|
||||
95 | value = 0
|
||||
96 | # ruff: enable[F841, RQW320]
|
||||
- # ruff: enable[YF829]
|
||||
97 |
|
||||
98 |
|
||||
99 | def f():
|
||||
|
||||
|
||||
RUF103 [*] Invalid suppression comment: missing suppression codes like `[E501, ...]`
|
||||
--> suppressions.py:109:5
|
||||
|
|
||||
|
||||
@@ -36,7 +36,6 @@ pub enum PythonVersion {
|
||||
Py312,
|
||||
Py313,
|
||||
Py314,
|
||||
Py315,
|
||||
}
|
||||
|
||||
impl Default for PythonVersion {
|
||||
@@ -59,7 +58,6 @@ impl TryFrom<ast::PythonVersion> for PythonVersion {
|
||||
ast::PythonVersion::PY312 => Ok(Self::Py312),
|
||||
ast::PythonVersion::PY313 => Ok(Self::Py313),
|
||||
ast::PythonVersion::PY314 => Ok(Self::Py314),
|
||||
ast::PythonVersion::PY315 => Ok(Self::Py315),
|
||||
_ => Err(format!("unrecognized python version {value}")),
|
||||
}
|
||||
}
|
||||
@@ -90,7 +88,6 @@ impl PythonVersion {
|
||||
Self::Py312 => (3, 12),
|
||||
Self::Py313 => (3, 13),
|
||||
Self::Py314 => (3, 14),
|
||||
Self::Py315 => (3, 15),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -607,21 +604,13 @@ impl TryFrom<String> for RequiredVersion {
|
||||
type Error = pep440_rs::VersionSpecifiersParseError;
|
||||
|
||||
fn try_from(value: String) -> Result<Self, Self::Error> {
|
||||
value.parse()
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for RequiredVersion {
|
||||
type Err = pep440_rs::VersionSpecifiersParseError;
|
||||
|
||||
fn from_str(value: &str) -> Result<Self, Self::Err> {
|
||||
// Treat `0.3.1` as `==0.3.1`, for backwards compatibility.
|
||||
if let Ok(version) = pep440_rs::Version::from_str(value) {
|
||||
if let Ok(version) = pep440_rs::Version::from_str(&value) {
|
||||
Ok(Self(VersionSpecifiers::from(
|
||||
VersionSpecifier::equals_version(version),
|
||||
)))
|
||||
} else {
|
||||
Ok(Self(VersionSpecifiers::from_str(value)?))
|
||||
Ok(Self(VersionSpecifiers::from_str(&value)?))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ use ruff_python_trivia::Cursor;
|
||||
use ruff_text_size::{Ranged, TextLen, TextRange, TextSize, TextSlice};
|
||||
use smallvec::{SmallVec, smallvec};
|
||||
|
||||
use crate::Locator;
|
||||
use crate::checkers::ast::LintContext;
|
||||
use crate::codes::Rule;
|
||||
use crate::fix::edits::delete_comment;
|
||||
@@ -23,7 +24,6 @@ use crate::rules::ruff::rules::{
|
||||
UnmatchedSuppressionComment, UnusedCodes, UnusedNOQA, UnusedNOQAKind, code_is_valid,
|
||||
};
|
||||
use crate::settings::LinterSettings;
|
||||
use crate::{Locator, Violation};
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
enum SuppressionAction {
|
||||
@@ -85,39 +85,11 @@ pub(crate) struct Suppression {
|
||||
/// Range for which the suppression applies
|
||||
range: TextRange,
|
||||
|
||||
/// Any comments associated with the suppression
|
||||
comments: SmallVec<[SuppressionComment; 2]>,
|
||||
|
||||
/// Whether this suppression actually suppressed a diagnostic
|
||||
used: Cell<bool>,
|
||||
|
||||
comments: DisableEnableComments,
|
||||
}
|
||||
|
||||
impl Suppression {
|
||||
fn codes(&self) -> &[TextRange] {
|
||||
&self.comments.disable_comment().codes
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) enum DisableEnableComments {
|
||||
/// An implicitly closed disable comment without a matching enable comment.
|
||||
Disable(SuppressionComment),
|
||||
/// A matching pair of disable and enable comments.
|
||||
DisableEnable(SuppressionComment, SuppressionComment),
|
||||
}
|
||||
|
||||
impl DisableEnableComments {
|
||||
pub(crate) fn disable_comment(&self) -> &SuppressionComment {
|
||||
match self {
|
||||
DisableEnableComments::Disable(comment) => comment,
|
||||
DisableEnableComments::DisableEnable(disable, _) => disable,
|
||||
}
|
||||
}
|
||||
pub(crate) fn enable_comment(&self) -> Option<&SuppressionComment> {
|
||||
match self {
|
||||
DisableEnableComments::Disable(_) => None,
|
||||
DisableEnableComments::DisableEnable(_, enable) => Some(enable),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
@@ -199,17 +171,23 @@ impl Suppressions {
|
||||
if !code_is_valid(&suppression.code, &context.settings().external) {
|
||||
// InvalidRuleCode
|
||||
if context.is_rule_enabled(Rule::InvalidRuleCode) {
|
||||
Suppressions::report_suppression(
|
||||
context,
|
||||
locator,
|
||||
suppression,
|
||||
true,
|
||||
InvalidRuleCode {
|
||||
rule_code: suppression.code.to_string(),
|
||||
kind: InvalidRuleCodeKind::Suppression,
|
||||
whole_comment: suppression.codes().len() == 1,
|
||||
},
|
||||
);
|
||||
for comment in &suppression.comments {
|
||||
let (range, edit) = Suppressions::delete_code_or_comment(
|
||||
locator,
|
||||
suppression,
|
||||
comment,
|
||||
true,
|
||||
);
|
||||
context
|
||||
.report_diagnostic(
|
||||
InvalidRuleCode {
|
||||
rule_code: suppression.code.to_string(),
|
||||
kind: InvalidRuleCodeKind::Suppression,
|
||||
},
|
||||
range,
|
||||
)
|
||||
.set_fix(Fix::safe_edit(edit));
|
||||
}
|
||||
}
|
||||
} else if !suppression.used.get() {
|
||||
// UnusedNOQA
|
||||
@@ -219,37 +197,42 @@ impl Suppressions {
|
||||
) else {
|
||||
continue; // "external" lint code, don't treat it as unused
|
||||
};
|
||||
for comment in &suppression.comments {
|
||||
let (range, edit) = Suppressions::delete_code_or_comment(
|
||||
locator,
|
||||
suppression,
|
||||
comment,
|
||||
false,
|
||||
);
|
||||
|
||||
let codes = if context.is_rule_enabled(rule) {
|
||||
UnusedCodes {
|
||||
unmatched: vec![suppression.code.to_string()],
|
||||
..Default::default()
|
||||
}
|
||||
} else {
|
||||
UnusedCodes {
|
||||
disabled: vec![suppression.code.to_string()],
|
||||
..Default::default()
|
||||
}
|
||||
};
|
||||
let codes = if context.is_rule_enabled(rule) {
|
||||
UnusedCodes {
|
||||
unmatched: vec![suppression.code.to_string()],
|
||||
..Default::default()
|
||||
}
|
||||
} else {
|
||||
UnusedCodes {
|
||||
disabled: vec![suppression.code.to_string()],
|
||||
..Default::default()
|
||||
}
|
||||
};
|
||||
|
||||
Suppressions::report_suppression(
|
||||
context,
|
||||
locator,
|
||||
suppression,
|
||||
false,
|
||||
UnusedNOQA {
|
||||
codes: Some(codes),
|
||||
kind: UnusedNOQAKind::Suppression,
|
||||
},
|
||||
);
|
||||
context
|
||||
.report_diagnostic(
|
||||
UnusedNOQA {
|
||||
codes: Some(codes),
|
||||
kind: UnusedNOQAKind::Suppression,
|
||||
},
|
||||
range,
|
||||
)
|
||||
.set_fix(Fix::safe_edit(edit));
|
||||
}
|
||||
}
|
||||
} else if let DisableEnableComments::Disable(comment) = &suppression.comments {
|
||||
} else if suppression.comments.len() == 1 {
|
||||
// UnmatchedSuppressionComment
|
||||
if unmatched_ranges.insert(comment.range) {
|
||||
context.report_diagnostic_if_enabled(
|
||||
UnmatchedSuppressionComment {},
|
||||
comment.range,
|
||||
);
|
||||
let range = suppression.comments[0].range;
|
||||
if unmatched_ranges.insert(range) {
|
||||
context.report_diagnostic_if_enabled(UnmatchedSuppressionComment {}, range);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -284,35 +267,6 @@ impl Suppressions {
|
||||
}
|
||||
}
|
||||
|
||||
fn report_suppression<T: Violation>(
|
||||
context: &LintContext,
|
||||
locator: &Locator,
|
||||
suppression: &Suppression,
|
||||
highlight_only_code: bool,
|
||||
kind: T,
|
||||
) {
|
||||
let disable_comment = suppression.comments.disable_comment();
|
||||
let (range, edit) = Suppressions::delete_code_or_comment(
|
||||
locator,
|
||||
suppression,
|
||||
disable_comment,
|
||||
highlight_only_code,
|
||||
);
|
||||
let mut diagnostic = context.report_diagnostic(kind, range);
|
||||
if let Some(enable_comment) = suppression.comments.enable_comment() {
|
||||
let (enable_range, enable_range_edit) = Suppressions::delete_code_or_comment(
|
||||
locator,
|
||||
suppression,
|
||||
enable_comment,
|
||||
highlight_only_code,
|
||||
);
|
||||
diagnostic.secondary_annotation("", enable_range);
|
||||
diagnostic.set_fix(Fix::safe_edits(edit, [enable_range_edit]));
|
||||
} else {
|
||||
diagnostic.set_fix(Fix::safe_edit(edit));
|
||||
}
|
||||
}
|
||||
|
||||
fn delete_code_or_comment(
|
||||
locator: &Locator<'_>,
|
||||
suppression: &Suppression,
|
||||
@@ -470,10 +424,7 @@ impl<'a> SuppressionsBuilder<'a> {
|
||||
self.valid.push(Suppression {
|
||||
code: code.into(),
|
||||
range: combined_range,
|
||||
comments: DisableEnableComments::DisableEnable(
|
||||
comment.comment.clone(),
|
||||
other.comment.clone(),
|
||||
),
|
||||
comments: smallvec![comment.comment.clone(), other.comment.clone()],
|
||||
used: false.into(),
|
||||
});
|
||||
}
|
||||
@@ -490,7 +441,7 @@ impl<'a> SuppressionsBuilder<'a> {
|
||||
self.valid.push(Suppression {
|
||||
code: code.into(),
|
||||
range: implicit_range,
|
||||
comments: DisableEnableComments::Disable(comment.comment.clone()),
|
||||
comments: smallvec![comment.comment.clone()],
|
||||
used: false.into(),
|
||||
});
|
||||
}
|
||||
@@ -692,7 +643,7 @@ mod tests {
|
||||
use insta::assert_debug_snapshot;
|
||||
use itertools::Itertools;
|
||||
use ruff_python_parser::{Mode, ParseOptions, parse};
|
||||
use ruff_text_size::{TextLen, TextRange, TextSize};
|
||||
use ruff_text_size::{TextRange, TextSize};
|
||||
use similar::DiffableStr;
|
||||
|
||||
use crate::{
|
||||
@@ -754,22 +705,24 @@ print('hello')
|
||||
Suppression {
|
||||
covered_source: "# ruff: disable[foo]\nprint('hello')\n# ruff: enable[foo]",
|
||||
code: "foo",
|
||||
disable_comment: SuppressionComment {
|
||||
text: "# ruff: disable[foo]",
|
||||
action: Disable,
|
||||
codes: [
|
||||
"foo",
|
||||
],
|
||||
reason: "",
|
||||
},
|
||||
enable_comment: SuppressionComment {
|
||||
text: "# ruff: enable[foo]",
|
||||
action: Enable,
|
||||
codes: [
|
||||
"foo",
|
||||
],
|
||||
reason: "",
|
||||
},
|
||||
comments: [
|
||||
SuppressionComment {
|
||||
text: "# ruff: disable[foo]",
|
||||
action: Disable,
|
||||
codes: [
|
||||
"foo",
|
||||
],
|
||||
reason: "",
|
||||
},
|
||||
SuppressionComment {
|
||||
text: "# ruff: enable[foo]",
|
||||
action: Enable,
|
||||
codes: [
|
||||
"foo",
|
||||
],
|
||||
reason: "",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
invalid: [],
|
||||
@@ -798,28 +751,30 @@ def foo():
|
||||
Suppression {
|
||||
covered_source: "# ruff: disable[bar]\n print('hello')\n\n",
|
||||
code: "bar",
|
||||
disable_comment: SuppressionComment {
|
||||
text: "# ruff: disable[bar]",
|
||||
action: Disable,
|
||||
codes: [
|
||||
"bar",
|
||||
],
|
||||
reason: "",
|
||||
},
|
||||
enable_comment: None,
|
||||
comments: [
|
||||
SuppressionComment {
|
||||
text: "# ruff: disable[bar]",
|
||||
action: Disable,
|
||||
codes: [
|
||||
"bar",
|
||||
],
|
||||
reason: "",
|
||||
},
|
||||
],
|
||||
},
|
||||
Suppression {
|
||||
covered_source: "# ruff: disable[foo]\nprint('hello')\n\ndef foo():\n # ruff: disable[bar]\n print('hello')\n\n",
|
||||
code: "foo",
|
||||
disable_comment: SuppressionComment {
|
||||
text: "# ruff: disable[foo]",
|
||||
action: Disable,
|
||||
codes: [
|
||||
"foo",
|
||||
],
|
||||
reason: "",
|
||||
},
|
||||
enable_comment: None,
|
||||
comments: [
|
||||
SuppressionComment {
|
||||
text: "# ruff: disable[foo]",
|
||||
action: Disable,
|
||||
codes: [
|
||||
"foo",
|
||||
],
|
||||
reason: "",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
invalid: [],
|
||||
@@ -848,42 +803,46 @@ class Foo:
|
||||
Suppression {
|
||||
covered_source: "# ruff: disable[bar]\n print('hello')\n # ruff: enable[bar]",
|
||||
code: "bar",
|
||||
disable_comment: SuppressionComment {
|
||||
text: "# ruff: disable[bar]",
|
||||
action: Disable,
|
||||
codes: [
|
||||
"bar",
|
||||
],
|
||||
reason: "",
|
||||
},
|
||||
enable_comment: SuppressionComment {
|
||||
text: "# ruff: enable[bar]",
|
||||
action: Enable,
|
||||
codes: [
|
||||
"bar",
|
||||
],
|
||||
reason: "",
|
||||
},
|
||||
comments: [
|
||||
SuppressionComment {
|
||||
text: "# ruff: disable[bar]",
|
||||
action: Disable,
|
||||
codes: [
|
||||
"bar",
|
||||
],
|
||||
reason: "",
|
||||
},
|
||||
SuppressionComment {
|
||||
text: "# ruff: enable[bar]",
|
||||
action: Enable,
|
||||
codes: [
|
||||
"bar",
|
||||
],
|
||||
reason: "",
|
||||
},
|
||||
],
|
||||
},
|
||||
Suppression {
|
||||
covered_source: "# ruff: disable[foo]\n def bar(self):\n # ruff: disable[bar]\n print('hello')\n # ruff: enable[bar]\n # ruff: enable[foo]",
|
||||
code: "foo",
|
||||
disable_comment: SuppressionComment {
|
||||
text: "# ruff: disable[foo]",
|
||||
action: Disable,
|
||||
codes: [
|
||||
"foo",
|
||||
],
|
||||
reason: "",
|
||||
},
|
||||
enable_comment: SuppressionComment {
|
||||
text: "# ruff: enable[foo]",
|
||||
action: Enable,
|
||||
codes: [
|
||||
"foo",
|
||||
],
|
||||
reason: "",
|
||||
},
|
||||
comments: [
|
||||
SuppressionComment {
|
||||
text: "# ruff: disable[foo]",
|
||||
action: Disable,
|
||||
codes: [
|
||||
"foo",
|
||||
],
|
||||
reason: "",
|
||||
},
|
||||
SuppressionComment {
|
||||
text: "# ruff: enable[foo]",
|
||||
action: Enable,
|
||||
codes: [
|
||||
"foo",
|
||||
],
|
||||
reason: "",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
invalid: [],
|
||||
@@ -913,42 +872,46 @@ def foo():
|
||||
Suppression {
|
||||
covered_source: "# ruff: disable[foo]\n print('hello')\n # ruff: disable[bar]\n print('hello')\n # ruff: enable[foo]",
|
||||
code: "foo",
|
||||
disable_comment: SuppressionComment {
|
||||
text: "# ruff: disable[foo]",
|
||||
action: Disable,
|
||||
codes: [
|
||||
"foo",
|
||||
],
|
||||
reason: "",
|
||||
},
|
||||
enable_comment: SuppressionComment {
|
||||
text: "# ruff: enable[foo]",
|
||||
action: Enable,
|
||||
codes: [
|
||||
"foo",
|
||||
],
|
||||
reason: "",
|
||||
},
|
||||
comments: [
|
||||
SuppressionComment {
|
||||
text: "# ruff: disable[foo]",
|
||||
action: Disable,
|
||||
codes: [
|
||||
"foo",
|
||||
],
|
||||
reason: "",
|
||||
},
|
||||
SuppressionComment {
|
||||
text: "# ruff: enable[foo]",
|
||||
action: Enable,
|
||||
codes: [
|
||||
"foo",
|
||||
],
|
||||
reason: "",
|
||||
},
|
||||
],
|
||||
},
|
||||
Suppression {
|
||||
covered_source: "# ruff: disable[bar]\n print('hello')\n # ruff: enable[foo]\n print('hello')\n # ruff: enable[bar]",
|
||||
code: "bar",
|
||||
disable_comment: SuppressionComment {
|
||||
text: "# ruff: disable[bar]",
|
||||
action: Disable,
|
||||
codes: [
|
||||
"bar",
|
||||
],
|
||||
reason: "",
|
||||
},
|
||||
enable_comment: SuppressionComment {
|
||||
text: "# ruff: enable[bar]",
|
||||
action: Enable,
|
||||
codes: [
|
||||
"bar",
|
||||
],
|
||||
reason: "",
|
||||
},
|
||||
comments: [
|
||||
SuppressionComment {
|
||||
text: "# ruff: disable[bar]",
|
||||
action: Disable,
|
||||
codes: [
|
||||
"bar",
|
||||
],
|
||||
reason: "",
|
||||
},
|
||||
SuppressionComment {
|
||||
text: "# ruff: enable[bar]",
|
||||
action: Enable,
|
||||
codes: [
|
||||
"bar",
|
||||
],
|
||||
reason: "",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
invalid: [],
|
||||
@@ -973,46 +936,50 @@ print('hello')
|
||||
Suppression {
|
||||
covered_source: "# ruff: disable[foo, bar]\nprint('hello')\n# ruff: enable[foo, bar]",
|
||||
code: "foo",
|
||||
disable_comment: SuppressionComment {
|
||||
text: "# ruff: disable[foo, bar]",
|
||||
action: Disable,
|
||||
codes: [
|
||||
"foo",
|
||||
"bar",
|
||||
],
|
||||
reason: "",
|
||||
},
|
||||
enable_comment: SuppressionComment {
|
||||
text: "# ruff: enable[foo, bar]",
|
||||
action: Enable,
|
||||
codes: [
|
||||
"foo",
|
||||
"bar",
|
||||
],
|
||||
reason: "",
|
||||
},
|
||||
comments: [
|
||||
SuppressionComment {
|
||||
text: "# ruff: disable[foo, bar]",
|
||||
action: Disable,
|
||||
codes: [
|
||||
"foo",
|
||||
"bar",
|
||||
],
|
||||
reason: "",
|
||||
},
|
||||
SuppressionComment {
|
||||
text: "# ruff: enable[foo, bar]",
|
||||
action: Enable,
|
||||
codes: [
|
||||
"foo",
|
||||
"bar",
|
||||
],
|
||||
reason: "",
|
||||
},
|
||||
],
|
||||
},
|
||||
Suppression {
|
||||
covered_source: "# ruff: disable[foo, bar]\nprint('hello')\n# ruff: enable[foo, bar]",
|
||||
code: "bar",
|
||||
disable_comment: SuppressionComment {
|
||||
text: "# ruff: disable[foo, bar]",
|
||||
action: Disable,
|
||||
codes: [
|
||||
"foo",
|
||||
"bar",
|
||||
],
|
||||
reason: "",
|
||||
},
|
||||
enable_comment: SuppressionComment {
|
||||
text: "# ruff: enable[foo, bar]",
|
||||
action: Enable,
|
||||
codes: [
|
||||
"foo",
|
||||
"bar",
|
||||
],
|
||||
reason: "",
|
||||
},
|
||||
comments: [
|
||||
SuppressionComment {
|
||||
text: "# ruff: disable[foo, bar]",
|
||||
action: Disable,
|
||||
codes: [
|
||||
"foo",
|
||||
"bar",
|
||||
],
|
||||
reason: "",
|
||||
},
|
||||
SuppressionComment {
|
||||
text: "# ruff: enable[foo, bar]",
|
||||
action: Enable,
|
||||
codes: [
|
||||
"foo",
|
||||
"bar",
|
||||
],
|
||||
reason: "",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
invalid: [],
|
||||
@@ -1038,15 +1005,16 @@ print('world')
|
||||
Suppression {
|
||||
covered_source: "# ruff: disable[foo]\nprint('hello')\n# ruff: enable[bar]\nprint('world')\n",
|
||||
code: "foo",
|
||||
disable_comment: SuppressionComment {
|
||||
text: "# ruff: disable[foo]",
|
||||
action: Disable,
|
||||
codes: [
|
||||
"foo",
|
||||
],
|
||||
reason: "",
|
||||
},
|
||||
enable_comment: None,
|
||||
comments: [
|
||||
SuppressionComment {
|
||||
text: "# ruff: disable[foo]",
|
||||
action: Disable,
|
||||
codes: [
|
||||
"foo",
|
||||
],
|
||||
reason: "",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
invalid: [
|
||||
@@ -1083,30 +1051,32 @@ print('hello')
|
||||
Suppression {
|
||||
covered_source: "# ruff: disable[foo, bar]\nprint('hello')\n# ruff: enable[bar, foo]\n",
|
||||
code: "foo",
|
||||
disable_comment: SuppressionComment {
|
||||
text: "# ruff: disable[foo, bar]",
|
||||
action: Disable,
|
||||
codes: [
|
||||
"foo",
|
||||
"bar",
|
||||
],
|
||||
reason: "",
|
||||
},
|
||||
enable_comment: None,
|
||||
comments: [
|
||||
SuppressionComment {
|
||||
text: "# ruff: disable[foo, bar]",
|
||||
action: Disable,
|
||||
codes: [
|
||||
"foo",
|
||||
"bar",
|
||||
],
|
||||
reason: "",
|
||||
},
|
||||
],
|
||||
},
|
||||
Suppression {
|
||||
covered_source: "# ruff: disable[foo, bar]\nprint('hello')\n# ruff: enable[bar, foo]\n",
|
||||
code: "bar",
|
||||
disable_comment: SuppressionComment {
|
||||
text: "# ruff: disable[foo, bar]",
|
||||
action: Disable,
|
||||
codes: [
|
||||
"foo",
|
||||
"bar",
|
||||
],
|
||||
reason: "",
|
||||
},
|
||||
enable_comment: None,
|
||||
comments: [
|
||||
SuppressionComment {
|
||||
text: "# ruff: disable[foo, bar]",
|
||||
action: Disable,
|
||||
codes: [
|
||||
"foo",
|
||||
"bar",
|
||||
],
|
||||
reason: "",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
invalid: [
|
||||
@@ -1146,35 +1116,38 @@ print('hello')
|
||||
Suppression {
|
||||
covered_source: "# ruff: disable[foo] first\nprint('hello')\n# ruff: disable[foo] second\nprint('hello')\n# ruff: enable[foo]",
|
||||
code: "foo",
|
||||
disable_comment: SuppressionComment {
|
||||
text: "# ruff: disable[foo] first",
|
||||
action: Disable,
|
||||
codes: [
|
||||
"foo",
|
||||
],
|
||||
reason: "first",
|
||||
},
|
||||
enable_comment: SuppressionComment {
|
||||
text: "# ruff: enable[foo]",
|
||||
action: Enable,
|
||||
codes: [
|
||||
"foo",
|
||||
],
|
||||
reason: "",
|
||||
},
|
||||
comments: [
|
||||
SuppressionComment {
|
||||
text: "# ruff: disable[foo] first",
|
||||
action: Disable,
|
||||
codes: [
|
||||
"foo",
|
||||
],
|
||||
reason: "first",
|
||||
},
|
||||
SuppressionComment {
|
||||
text: "# ruff: enable[foo]",
|
||||
action: Enable,
|
||||
codes: [
|
||||
"foo",
|
||||
],
|
||||
reason: "",
|
||||
},
|
||||
],
|
||||
},
|
||||
Suppression {
|
||||
covered_source: "# ruff: disable[foo] second\nprint('hello')\n# ruff: enable[foo]\n",
|
||||
code: "foo",
|
||||
disable_comment: SuppressionComment {
|
||||
text: "# ruff: disable[foo] second",
|
||||
action: Disable,
|
||||
codes: [
|
||||
"foo",
|
||||
],
|
||||
reason: "second",
|
||||
},
|
||||
enable_comment: None,
|
||||
comments: [
|
||||
SuppressionComment {
|
||||
text: "# ruff: disable[foo] second",
|
||||
action: Disable,
|
||||
codes: [
|
||||
"foo",
|
||||
],
|
||||
reason: "second",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
invalid: [],
|
||||
@@ -1216,92 +1189,100 @@ def bar():
|
||||
Suppression {
|
||||
covered_source: "# ruff: disable[delta] unmatched\n pass\n # ruff: enable[beta,gamma]\n# ruff: enable[alpha]\n\n# ruff: disable # parse error!\n",
|
||||
code: "delta",
|
||||
disable_comment: SuppressionComment {
|
||||
text: "# ruff: disable[delta] unmatched",
|
||||
action: Disable,
|
||||
codes: [
|
||||
"delta",
|
||||
],
|
||||
reason: "unmatched",
|
||||
},
|
||||
enable_comment: None,
|
||||
comments: [
|
||||
SuppressionComment {
|
||||
text: "# ruff: disable[delta] unmatched",
|
||||
action: Disable,
|
||||
codes: [
|
||||
"delta",
|
||||
],
|
||||
reason: "unmatched",
|
||||
},
|
||||
],
|
||||
},
|
||||
Suppression {
|
||||
covered_source: "# ruff: disable[beta,gamma]\n if True:\n # ruff: disable[delta] unmatched\n pass\n # ruff: enable[beta,gamma]",
|
||||
code: "beta",
|
||||
disable_comment: SuppressionComment {
|
||||
text: "# ruff: disable[beta,gamma]",
|
||||
action: Disable,
|
||||
codes: [
|
||||
"beta",
|
||||
"gamma",
|
||||
],
|
||||
reason: "",
|
||||
},
|
||||
enable_comment: SuppressionComment {
|
||||
text: "# ruff: enable[beta,gamma]",
|
||||
action: Enable,
|
||||
codes: [
|
||||
"beta",
|
||||
"gamma",
|
||||
],
|
||||
reason: "",
|
||||
},
|
||||
comments: [
|
||||
SuppressionComment {
|
||||
text: "# ruff: disable[beta,gamma]",
|
||||
action: Disable,
|
||||
codes: [
|
||||
"beta",
|
||||
"gamma",
|
||||
],
|
||||
reason: "",
|
||||
},
|
||||
SuppressionComment {
|
||||
text: "# ruff: enable[beta,gamma]",
|
||||
action: Enable,
|
||||
codes: [
|
||||
"beta",
|
||||
"gamma",
|
||||
],
|
||||
reason: "",
|
||||
},
|
||||
],
|
||||
},
|
||||
Suppression {
|
||||
covered_source: "# ruff: disable[beta,gamma]\n if True:\n # ruff: disable[delta] unmatched\n pass\n # ruff: enable[beta,gamma]",
|
||||
code: "gamma",
|
||||
disable_comment: SuppressionComment {
|
||||
text: "# ruff: disable[beta,gamma]",
|
||||
action: Disable,
|
||||
codes: [
|
||||
"beta",
|
||||
"gamma",
|
||||
],
|
||||
reason: "",
|
||||
},
|
||||
enable_comment: SuppressionComment {
|
||||
text: "# ruff: enable[beta,gamma]",
|
||||
action: Enable,
|
||||
codes: [
|
||||
"beta",
|
||||
"gamma",
|
||||
],
|
||||
reason: "",
|
||||
},
|
||||
comments: [
|
||||
SuppressionComment {
|
||||
text: "# ruff: disable[beta,gamma]",
|
||||
action: Disable,
|
||||
codes: [
|
||||
"beta",
|
||||
"gamma",
|
||||
],
|
||||
reason: "",
|
||||
},
|
||||
SuppressionComment {
|
||||
text: "# ruff: enable[beta,gamma]",
|
||||
action: Enable,
|
||||
codes: [
|
||||
"beta",
|
||||
"gamma",
|
||||
],
|
||||
reason: "",
|
||||
},
|
||||
],
|
||||
},
|
||||
Suppression {
|
||||
covered_source: "# ruff: disable[zeta] unmatched\n pass\n# ruff: enable[zeta] underindented\n pass\n",
|
||||
code: "zeta",
|
||||
disable_comment: SuppressionComment {
|
||||
text: "# ruff: disable[zeta] unmatched",
|
||||
action: Disable,
|
||||
codes: [
|
||||
"zeta",
|
||||
],
|
||||
reason: "unmatched",
|
||||
},
|
||||
enable_comment: None,
|
||||
comments: [
|
||||
SuppressionComment {
|
||||
text: "# ruff: disable[zeta] unmatched",
|
||||
action: Disable,
|
||||
codes: [
|
||||
"zeta",
|
||||
],
|
||||
reason: "unmatched",
|
||||
},
|
||||
],
|
||||
},
|
||||
Suppression {
|
||||
covered_source: "# ruff: disable[alpha]\ndef foo():\n # ruff: disable[beta,gamma]\n if True:\n # ruff: disable[delta] unmatched\n pass\n # ruff: enable[beta,gamma]\n# ruff: enable[alpha]",
|
||||
code: "alpha",
|
||||
disable_comment: SuppressionComment {
|
||||
text: "# ruff: disable[alpha]",
|
||||
action: Disable,
|
||||
codes: [
|
||||
"alpha",
|
||||
],
|
||||
reason: "",
|
||||
},
|
||||
enable_comment: SuppressionComment {
|
||||
text: "# ruff: enable[alpha]",
|
||||
action: Enable,
|
||||
codes: [
|
||||
"alpha",
|
||||
],
|
||||
reason: "",
|
||||
},
|
||||
comments: [
|
||||
SuppressionComment {
|
||||
text: "# ruff: disable[alpha]",
|
||||
action: Disable,
|
||||
codes: [
|
||||
"alpha",
|
||||
],
|
||||
reason: "",
|
||||
},
|
||||
SuppressionComment {
|
||||
text: "# ruff: enable[alpha]",
|
||||
action: Enable,
|
||||
codes: [
|
||||
"alpha",
|
||||
],
|
||||
reason: "",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
invalid: [
|
||||
@@ -1551,8 +1532,10 @@ def bar():
|
||||
#[test]
|
||||
fn comment_attributes() {
|
||||
let source = "# ruff: disable[foo, bar] hello world";
|
||||
let mut parser =
|
||||
SuppressionParser::new(source, TextRange::new(0.into(), source.text_len()));
|
||||
let mut parser = SuppressionParser::new(
|
||||
source,
|
||||
TextRange::new(0.into(), TextSize::try_from(source.len()).unwrap()),
|
||||
);
|
||||
let comment = parser.parse_comment().unwrap();
|
||||
assert_eq!(comment.action, SuppressionAction::Disable);
|
||||
assert_eq!(
|
||||
@@ -1571,12 +1554,12 @@ def bar():
|
||||
source: &'_ str,
|
||||
) -> Result<DebugSuppressionComment<'_>, ParseError> {
|
||||
let offset = TextSize::new(source.find('#').unwrap_or(0).try_into().unwrap());
|
||||
let mut parser = SuppressionParser::new(source, TextRange::new(offset, source.text_len()));
|
||||
let mut parser = SuppressionParser::new(
|
||||
source,
|
||||
TextRange::new(offset, TextSize::try_from(source.len()).unwrap()),
|
||||
);
|
||||
match parser.parse_comment() {
|
||||
Ok(comment) => Ok(DebugSuppressionComment {
|
||||
source,
|
||||
comment: Some(comment),
|
||||
}),
|
||||
Ok(comment) => Ok(DebugSuppressionComment { source, comment }),
|
||||
Err(error) => Err(error),
|
||||
}
|
||||
}
|
||||
@@ -1656,18 +1639,16 @@ def bar():
|
||||
.field("covered_source", &&self.source[self.suppression.range])
|
||||
.field("code", &self.suppression.code)
|
||||
.field(
|
||||
"disable_comment",
|
||||
&DebugSuppressionComment {
|
||||
source: self.source,
|
||||
comment: Some(self.suppression.comments.disable_comment().clone()),
|
||||
},
|
||||
)
|
||||
.field(
|
||||
"enable_comment",
|
||||
&DebugSuppressionComment {
|
||||
source: self.source,
|
||||
comment: self.suppression.comments.enable_comment().cloned(),
|
||||
},
|
||||
"comments",
|
||||
&self
|
||||
.suppression
|
||||
.comments
|
||||
.iter()
|
||||
.map(|comment| DebugSuppressionComment {
|
||||
source: self.source,
|
||||
comment: comment.clone(),
|
||||
})
|
||||
.collect_vec(),
|
||||
)
|
||||
.finish()
|
||||
}
|
||||
@@ -1686,7 +1667,7 @@ def bar():
|
||||
"comment",
|
||||
&DebugSuppressionComment {
|
||||
source: self.source,
|
||||
comment: Some(self.invalid.comment.clone()),
|
||||
comment: self.invalid.comment.clone(),
|
||||
},
|
||||
)
|
||||
.finish()
|
||||
@@ -1709,27 +1690,23 @@ def bar():
|
||||
|
||||
struct DebugSuppressionComment<'a> {
|
||||
source: &'a str,
|
||||
comment: Option<SuppressionComment>,
|
||||
comment: SuppressionComment,
|
||||
}
|
||||
|
||||
impl fmt::Debug for DebugSuppressionComment<'_> {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
match &self.comment {
|
||||
Some(comment) => f
|
||||
.debug_struct("SuppressionComment")
|
||||
.field("text", &&self.source[comment.range])
|
||||
.field("action", &comment.action)
|
||||
.field(
|
||||
"codes",
|
||||
&DebugCodes {
|
||||
source: self.source,
|
||||
codes: &comment.codes,
|
||||
},
|
||||
)
|
||||
.field("reason", &&self.source[comment.reason])
|
||||
.finish(),
|
||||
None => f.debug_tuple("None").finish(),
|
||||
}
|
||||
f.debug_struct("SuppressionComment")
|
||||
.field("text", &&self.source[self.comment.range])
|
||||
.field("action", &self.comment.action)
|
||||
.field(
|
||||
"codes",
|
||||
&DebugCodes {
|
||||
source: self.source,
|
||||
codes: &self.comment.codes,
|
||||
},
|
||||
)
|
||||
.field("reason", &&self.source[self.comment.reason])
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -35,10 +35,6 @@ impl PythonVersion {
|
||||
major: 3,
|
||||
minor: 14,
|
||||
};
|
||||
pub const PY315: PythonVersion = PythonVersion {
|
||||
major: 3,
|
||||
minor: 15,
|
||||
};
|
||||
|
||||
pub fn iter() -> impl Iterator<Item = PythonVersion> {
|
||||
[
|
||||
@@ -50,7 +46,6 @@ impl PythonVersion {
|
||||
PythonVersion::PY312,
|
||||
PythonVersion::PY313,
|
||||
PythonVersion::PY314,
|
||||
PythonVersion::PY315,
|
||||
]
|
||||
.into_iter()
|
||||
}
|
||||
@@ -66,7 +61,7 @@ impl PythonVersion {
|
||||
|
||||
/// The latest Python version supported in preview
|
||||
pub fn latest_preview() -> Self {
|
||||
let latest_preview = Self::PY315;
|
||||
let latest_preview = Self::PY314;
|
||||
debug_assert!(latest_preview >= Self::latest());
|
||||
latest_preview
|
||||
}
|
||||
|
||||
@@ -91,22 +91,20 @@ def example(session):
|
||||
.all()
|
||||
# fmt: on
|
||||
def off_and_on_without_data():
|
||||
"""Test that comment-only fmt:off/on blocks preserve formatting."""
|
||||
# fmt: off
|
||||
#should not be formatted
|
||||
# fmt: on
|
||||
"""All comments here are technically on the same prefix.
|
||||
|
||||
The comments between will be formatted. This is a known limitation.
|
||||
"""
|
||||
# fmt: off
|
||||
|
||||
#should not be formatted
|
||||
|
||||
# fmt: on
|
||||
# fmt: off
|
||||
#should not be formatted
|
||||
#should not be formatted #also should not be formatted
|
||||
#hey, that won't work
|
||||
|
||||
|
||||
# fmt: on
|
||||
pass
|
||||
def on_and_off_with_comment_only_blocks():
|
||||
"""Test that fmt:off/on works with multiple directives and comment-only blocks."""
|
||||
def on_and_off_broken():
|
||||
"""Another known limitation."""
|
||||
# fmt: on
|
||||
# fmt: off
|
||||
this=should.not_be.formatted()
|
||||
@@ -115,16 +113,7 @@ def on_and_off_with_comment_only_blocks():
|
||||
now . considers . multiple . fmt . directives . within . one . prefix
|
||||
# fmt: on
|
||||
# fmt: off
|
||||
#should not be formatted
|
||||
# fmt: on
|
||||
# fmt: off
|
||||
|
||||
#should not be formatted
|
||||
|
||||
# fmt: on
|
||||
# fmt: off
|
||||
#should not be formatted
|
||||
#should not be formatted #also should not be formatted
|
||||
# ...but comments still get reformatted even though they should not be
|
||||
# fmt: on
|
||||
def long_lines():
|
||||
if True:
|
||||
@@ -189,50 +178,6 @@ cfg.rule(
|
||||
# fmt: on
|
||||
xxxxxxxxxx_xxxxxxxxxxx_xxxxxxx_xxxxxxxxx=5
|
||||
)
|
||||
|
||||
# Test comment-only blocks at file level with various spacing patterns
|
||||
# fmt: off
|
||||
#nospace
|
||||
# twospaces
|
||||
# fmt: on
|
||||
|
||||
|
||||
# fmt: off
|
||||
#nospaceatall
|
||||
#extraspaces
|
||||
#evenmorespaces
|
||||
# fmt: on
|
||||
|
||||
|
||||
# fmt: off
|
||||
# fmt: on
|
||||
|
||||
|
||||
# fmt: off
|
||||
#SBATCH --job-name=test
|
||||
#SBATCH --output=test.out
|
||||
# fmt: on
|
||||
|
||||
|
||||
# fmt: off
|
||||
#first
|
||||
|
||||
#second
|
||||
# fmt: on
|
||||
|
||||
|
||||
# fmt: off
|
||||
#!@#$%^&*()
|
||||
#<=>+-*/
|
||||
# fmt: on
|
||||
|
||||
|
||||
# fmt: off
|
||||
#x=1+2
|
||||
#y = 3
|
||||
#z = 4
|
||||
# fmt: on
|
||||
|
||||
# fmt: off
|
||||
yield 'hello'
|
||||
# No formatting to the end of the file
|
||||
|
||||
@@ -112,42 +112,29 @@ def example(session):
|
||||
|
||||
|
||||
def off_and_on_without_data():
|
||||
"""Test that comment-only fmt:off/on blocks preserve formatting."""
|
||||
# fmt: off
|
||||
#should not be formatted
|
||||
# fmt: on
|
||||
"""All comments here are technically on the same prefix.
|
||||
|
||||
The comments between will be formatted. This is a known limitation.
|
||||
"""
|
||||
# fmt: off
|
||||
|
||||
#should not be formatted
|
||||
# hey, that won't work
|
||||
|
||||
# fmt: on
|
||||
# fmt: off
|
||||
#should not be formatted
|
||||
#should not be formatted #also should not be formatted
|
||||
# fmt: on
|
||||
pass
|
||||
|
||||
|
||||
def on_and_off_with_comment_only_blocks():
|
||||
"""Test that fmt:off/on works with multiple directives and comment-only blocks."""
|
||||
def on_and_off_broken():
|
||||
"""Another known limitation."""
|
||||
# fmt: on
|
||||
# fmt: off
|
||||
this=should.not_be.formatted()
|
||||
and_=indeed . it is not formatted
|
||||
because . the . handling . inside . generate_ignored_nodes()
|
||||
now . considers . multiple . fmt . directives . within . one . prefix
|
||||
|
||||
# fmt: off
|
||||
#should not be formatted
|
||||
# fmt: on
|
||||
# fmt: off
|
||||
|
||||
#should not be formatted
|
||||
|
||||
# fmt: on
|
||||
# fmt: off
|
||||
#should not be formatted
|
||||
#should not be formatted #also should not be formatted
|
||||
# ...but comments still get reformatted even though they should not be
|
||||
# fmt: on
|
||||
|
||||
|
||||
@@ -224,50 +211,6 @@ cfg.rule(
|
||||
# fmt: on
|
||||
xxxxxxxxxx_xxxxxxxxxxx_xxxxxxx_xxxxxxxxx=5,
|
||||
)
|
||||
|
||||
# Test comment-only blocks at file level with various spacing patterns
|
||||
# fmt: off
|
||||
#nospace
|
||||
# twospaces
|
||||
# fmt: on
|
||||
|
||||
|
||||
# fmt: off
|
||||
#nospaceatall
|
||||
#extraspaces
|
||||
#evenmorespaces
|
||||
# fmt: on
|
||||
|
||||
|
||||
# fmt: off
|
||||
# fmt: on
|
||||
|
||||
|
||||
# fmt: off
|
||||
#SBATCH --job-name=test
|
||||
#SBATCH --output=test.out
|
||||
# fmt: on
|
||||
|
||||
|
||||
# fmt: off
|
||||
#first
|
||||
|
||||
#second
|
||||
# fmt: on
|
||||
|
||||
|
||||
# fmt: off
|
||||
#!@#$%^&*()
|
||||
#<=>+-*/
|
||||
# fmt: on
|
||||
|
||||
|
||||
# fmt: off
|
||||
#x=1+2
|
||||
#y = 3
|
||||
#z = 4
|
||||
# fmt: on
|
||||
|
||||
# fmt: off
|
||||
yield 'hello'
|
||||
# No formatting to the end of the file
|
||||
|
||||
@@ -1,21 +1,8 @@
|
||||
def foo(): return "mock" # fmt: skip
|
||||
if True: print("yay") # fmt: skip
|
||||
for i in range(10): print(i) # fmt: skip
|
||||
if True: print("this"); print("that") # fmt: skip
|
||||
while True: print("loop"); break # fmt: skip
|
||||
for x in [1, 2]: print(x); print("done") # fmt: skip
|
||||
def f(x: int): return x # fmt: skip
|
||||
|
||||
j = 1 # fmt: skip
|
||||
while j < 10: j += 1 # fmt: skip
|
||||
|
||||
b = [c for c in "A very long string that would normally generate some kind of collapse, since it is this long"] # fmt: skip
|
||||
|
||||
v = (
|
||||
foo_dict # fmt: skip
|
||||
.setdefault("a", {})
|
||||
.setdefault("b", {})
|
||||
.setdefault("c", {})
|
||||
.setdefault("d", {})
|
||||
.setdefault("e", {})
|
||||
)
|
||||
|
||||
@@ -1,21 +1,8 @@
|
||||
def foo(): return "mock" # fmt: skip
|
||||
if True: print("yay") # fmt: skip
|
||||
for i in range(10): print(i) # fmt: skip
|
||||
if True: print("this"); print("that") # fmt: skip
|
||||
while True: print("loop"); break # fmt: skip
|
||||
for x in [1, 2]: print(x); print("done") # fmt: skip
|
||||
def f(x: int): return x # fmt: skip
|
||||
|
||||
j = 1 # fmt: skip
|
||||
while j < 10: j += 1 # fmt: skip
|
||||
|
||||
b = [c for c in "A very long string that would normally generate some kind of collapse, since it is this long"] # fmt: skip
|
||||
|
||||
v = (
|
||||
foo_dict # fmt: skip
|
||||
.setdefault("a", {})
|
||||
.setdefault("b", {})
|
||||
.setdefault("c", {})
|
||||
.setdefault("d", {})
|
||||
.setdefault("e", {})
|
||||
)
|
||||
|
||||
@@ -4,84 +4,3 @@ def foo():
|
||||
|
||||
# comment 1 # fmt: skip
|
||||
# comment 2
|
||||
|
||||
[
|
||||
(1, 2),
|
||||
# # fmt: off
|
||||
# (3,
|
||||
# 4),
|
||||
# # fmt: on
|
||||
(5, 6),
|
||||
]
|
||||
|
||||
[
|
||||
(1, 2),
|
||||
# # fmt: off
|
||||
# (3,
|
||||
# 4),
|
||||
# fmt: on
|
||||
(5, 6),
|
||||
]
|
||||
|
||||
|
||||
[
|
||||
(1, 2),
|
||||
# fmt: off
|
||||
# (3,
|
||||
# 4),
|
||||
# # fmt: on
|
||||
(5, 6),
|
||||
]
|
||||
|
||||
|
||||
[
|
||||
(1, 2),
|
||||
# fmt: off
|
||||
# (3,
|
||||
# 4),
|
||||
# fmt: on
|
||||
(5, 6),
|
||||
]
|
||||
|
||||
[
|
||||
(1, 2),
|
||||
# # fmt: off
|
||||
(3,
|
||||
4),
|
||||
# # fmt: on
|
||||
(5, 6),
|
||||
]
|
||||
|
||||
[
|
||||
(1, 2),
|
||||
# # fmt: off
|
||||
(3,
|
||||
4),
|
||||
# fmt: on
|
||||
(5, 6),
|
||||
]
|
||||
|
||||
|
||||
[
|
||||
(1, 2),
|
||||
# fmt: off
|
||||
(3,
|
||||
4),
|
||||
# # fmt: on
|
||||
(5, 6),
|
||||
]
|
||||
|
||||
|
||||
[
|
||||
(1, 2),
|
||||
# fmt: off
|
||||
(3,
|
||||
4),
|
||||
# fmt: on
|
||||
(5, 6),
|
||||
]
|
||||
|
||||
|
||||
if False:
|
||||
# fmt: off # some other comment
|
||||
pass
|
||||
|
||||
@@ -4,84 +4,3 @@ def foo():
|
||||
|
||||
# comment 1 # fmt: skip
|
||||
# comment 2
|
||||
|
||||
[
|
||||
(1, 2),
|
||||
# # fmt: off
|
||||
# (3,
|
||||
# 4),
|
||||
# # fmt: on
|
||||
(5, 6),
|
||||
]
|
||||
|
||||
[
|
||||
(1, 2),
|
||||
# # fmt: off
|
||||
# (3,
|
||||
# 4),
|
||||
# fmt: on
|
||||
(5, 6),
|
||||
]
|
||||
|
||||
|
||||
[
|
||||
(1, 2),
|
||||
# fmt: off
|
||||
# (3,
|
||||
# 4),
|
||||
# # fmt: on
|
||||
(5, 6),
|
||||
]
|
||||
|
||||
|
||||
[
|
||||
(1, 2),
|
||||
# fmt: off
|
||||
# (3,
|
||||
# 4),
|
||||
# fmt: on
|
||||
(5, 6),
|
||||
]
|
||||
|
||||
[
|
||||
(1, 2),
|
||||
# # fmt: off
|
||||
(3,
|
||||
4),
|
||||
# # fmt: on
|
||||
(5, 6),
|
||||
]
|
||||
|
||||
[
|
||||
(1, 2),
|
||||
# # fmt: off
|
||||
(3,
|
||||
4),
|
||||
# fmt: on
|
||||
(5, 6),
|
||||
]
|
||||
|
||||
|
||||
[
|
||||
(1, 2),
|
||||
# fmt: off
|
||||
(3,
|
||||
4),
|
||||
# # fmt: on
|
||||
(5, 6),
|
||||
]
|
||||
|
||||
|
||||
[
|
||||
(1, 2),
|
||||
# fmt: off
|
||||
(3,
|
||||
4),
|
||||
# fmt: on
|
||||
(5, 6),
|
||||
]
|
||||
|
||||
|
||||
if False:
|
||||
# fmt: off # some other comment
|
||||
pass
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
{"preview": "enabled"}
|
||||
@@ -1,8 +0,0 @@
|
||||
with open("file.txt") as f: content = f.read() # fmt: skip
|
||||
|
||||
# Ideally, only the last line would be ignored
|
||||
# But ignoring only part of the asexpr_test causes a parse error
|
||||
# Same with ignoring the asexpr_test without also ignoring the entire with_stmt
|
||||
with open (
|
||||
"file.txt" ,
|
||||
) as f: content = f.read() # fmt: skip
|
||||
@@ -1,8 +0,0 @@
|
||||
with open("file.txt") as f: content = f.read() # fmt: skip
|
||||
|
||||
# Ideally, only the last line would be ignored
|
||||
# But ignoring only part of the asexpr_test causes a parse error
|
||||
# Same with ignoring the asexpr_test without also ignoring the entire with_stmt
|
||||
with open (
|
||||
"file.txt" ,
|
||||
) as f: content = f.read() # fmt: skip
|
||||
@@ -1 +0,0 @@
|
||||
{"preview": "enabled"}
|
||||
@@ -1,28 +0,0 @@
|
||||
t = (
|
||||
{"foo": "very long string", "bar": "another very long string", "baz": "we should run out of space by now"}, # fmt: skip
|
||||
{"foo": "bar"},
|
||||
)
|
||||
|
||||
t = (
|
||||
{
|
||||
"foo": "very long string",
|
||||
"bar": "another very long string",
|
||||
"baz": "we should run out of space by now",
|
||||
}, # fmt: skip
|
||||
{"foo": "bar"},
|
||||
)
|
||||
|
||||
|
||||
t = (
|
||||
{"foo": "very long string", "bar": "another very long string", "baz": "we should run out of space by now"}, # fmt: skip
|
||||
{"foo": "bar",},
|
||||
)
|
||||
|
||||
t = (
|
||||
{
|
||||
"foo": "very long string",
|
||||
"bar": "another very long string",
|
||||
"baz": "we should run out of space by now",
|
||||
}, # fmt: skip
|
||||
{"foo": "bar",},
|
||||
)
|
||||
@@ -1,32 +0,0 @@
|
||||
t = (
|
||||
{"foo": "very long string", "bar": "another very long string", "baz": "we should run out of space by now"}, # fmt: skip
|
||||
{"foo": "bar"},
|
||||
)
|
||||
|
||||
t = (
|
||||
{
|
||||
"foo": "very long string",
|
||||
"bar": "another very long string",
|
||||
"baz": "we should run out of space by now",
|
||||
}, # fmt: skip
|
||||
{"foo": "bar"},
|
||||
)
|
||||
|
||||
|
||||
t = (
|
||||
{"foo": "very long string", "bar": "another very long string", "baz": "we should run out of space by now"}, # fmt: skip
|
||||
{
|
||||
"foo": "bar",
|
||||
},
|
||||
)
|
||||
|
||||
t = (
|
||||
{
|
||||
"foo": "very long string",
|
||||
"bar": "another very long string",
|
||||
"baz": "we should run out of space by now",
|
||||
}, # fmt: skip
|
||||
{
|
||||
"foo": "bar",
|
||||
},
|
||||
)
|
||||
@@ -1,4 +1,4 @@
|
||||
a = "this is some code"
|
||||
b = 5 # fmt:skip
|
||||
b = 5 #fmt:skip
|
||||
c = 9 #fmt: skip
|
||||
d = "thisisasuperlongstringthisisasuperlongstringthisisasuperlongstringthisisasuperlongstring" # fmt:skip
|
||||
d = "thisisasuperlongstringthisisasuperlongstringthisisasuperlongstringthisisasuperlongstring" #fmt:skip
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
a = "this is some code"
|
||||
b = 5 # fmt:skip
|
||||
c = 9 #fmt: skip
|
||||
d = "thisisasuperlongstringthisisasuperlongstringthisisasuperlongstringthisisasuperlongstring" # fmt:skip
|
||||
b = 5 # fmt:skip
|
||||
c = 9 # fmt: skip
|
||||
d = "thisisasuperlongstringthisisasuperlongstringthisisasuperlongstringthisisasuperlongstring" # fmt:skip
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
# Multiple fmt: skip in multi-part if-clause
|
||||
class ClassWithALongName:
|
||||
Constant1 = 1
|
||||
Constant2 = 2
|
||||
Constant3 = 3
|
||||
|
||||
|
||||
def test():
|
||||
if (
|
||||
"cond1" == "cond1"
|
||||
and "cond2" == "cond2"
|
||||
and 1 in (
|
||||
ClassWithALongName.Constant1,
|
||||
ClassWithALongName.Constant2,
|
||||
ClassWithALongName.Constant3, # fmt: skip
|
||||
) # fmt: skip
|
||||
):
|
||||
return True
|
||||
return False
|
||||
@@ -1,19 +0,0 @@
|
||||
# Multiple fmt: skip in multi-part if-clause
|
||||
class ClassWithALongName:
|
||||
Constant1 = 1
|
||||
Constant2 = 2
|
||||
Constant3 = 3
|
||||
|
||||
|
||||
def test():
|
||||
if (
|
||||
"cond1" == "cond1"
|
||||
and "cond2" == "cond2"
|
||||
and 1 in (
|
||||
ClassWithALongName.Constant1,
|
||||
ClassWithALongName.Constant2,
|
||||
ClassWithALongName.Constant3, # fmt: skip
|
||||
) # fmt: skip
|
||||
):
|
||||
return True
|
||||
return False
|
||||
@@ -1,35 +0,0 @@
|
||||
# Multiple fmt: skip on string literals
|
||||
a = (
|
||||
"this should " # fmt: skip
|
||||
"be fine"
|
||||
)
|
||||
|
||||
b = (
|
||||
"this is " # fmt: skip
|
||||
"not working" # fmt: skip
|
||||
)
|
||||
|
||||
c = (
|
||||
"and neither " # fmt: skip
|
||||
"is this " # fmt: skip
|
||||
"working"
|
||||
)
|
||||
|
||||
d = (
|
||||
"nor "
|
||||
"is this " # fmt: skip
|
||||
"working" # fmt: skip
|
||||
)
|
||||
|
||||
e = (
|
||||
"and this " # fmt: skip
|
||||
"is definitely "
|
||||
"not working" # fmt: skip
|
||||
)
|
||||
|
||||
# Dictionary entries with fmt: skip (covers issue with long lines)
|
||||
hotkeys = {
|
||||
"editor:swap-line-down": [{"key": "ArrowDown", "modifiers": ["Alt", "Mod"]}], # fmt: skip
|
||||
"editor:swap-line-up": [{"key": "ArrowUp", "modifiers": ["Alt", "Mod"]}], # fmt: skip
|
||||
"editor:toggle-source": [{"key": "S", "modifiers": ["Alt", "Mod"]}], # fmt: skip
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
# Multiple fmt: skip on string literals
|
||||
a = (
|
||||
"this should " # fmt: skip
|
||||
"be fine"
|
||||
)
|
||||
|
||||
b = (
|
||||
"this is " # fmt: skip
|
||||
"not working" # fmt: skip
|
||||
)
|
||||
|
||||
c = (
|
||||
"and neither " # fmt: skip
|
||||
"is this " # fmt: skip
|
||||
"working"
|
||||
)
|
||||
|
||||
d = (
|
||||
"nor "
|
||||
"is this " # fmt: skip
|
||||
"working" # fmt: skip
|
||||
)
|
||||
|
||||
e = (
|
||||
"and this " # fmt: skip
|
||||
"is definitely "
|
||||
"not working" # fmt: skip
|
||||
)
|
||||
|
||||
# Dictionary entries with fmt: skip (covers issue with long lines)
|
||||
hotkeys = {
|
||||
"editor:swap-line-down": [{"key": "ArrowDown", "modifiers": ["Alt", "Mod"]}], # fmt: skip
|
||||
"editor:swap-line-up": [{"key": "ArrowUp", "modifiers": ["Alt", "Mod"]}], # fmt: skip
|
||||
"editor:toggle-source": [{"key": "S", "modifiers": ["Alt", "Mod"]}], # fmt: skip
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
# Test that Jupytext markdown comments are preserved before fmt:off/on blocks
|
||||
# %% [markdown]
|
||||
|
||||
# fmt: off
|
||||
# fmt: on
|
||||
|
||||
# Also test with other comments
|
||||
# Some comment
|
||||
# %% [markdown]
|
||||
# Another comment
|
||||
|
||||
# fmt: off
|
||||
x = 1
|
||||
# fmt: on
|
||||
|
||||
# Test multiple markdown comments
|
||||
# %% [markdown]
|
||||
# First markdown
|
||||
# %% [code]
|
||||
# Code cell
|
||||
|
||||
# fmt: off
|
||||
y = 2
|
||||
# fmt: on
|
||||
@@ -1,24 +0,0 @@
|
||||
# Test that Jupytext markdown comments are preserved before fmt:off/on blocks
|
||||
# %% [markdown]
|
||||
|
||||
# fmt: off
|
||||
# fmt: on
|
||||
|
||||
# Also test with other comments
|
||||
# Some comment
|
||||
# %% [markdown]
|
||||
# Another comment
|
||||
|
||||
# fmt: off
|
||||
x = 1
|
||||
# fmt: on
|
||||
|
||||
# Test multiple markdown comments
|
||||
# %% [markdown]
|
||||
# First markdown
|
||||
# %% [code]
|
||||
# Code cell
|
||||
|
||||
# fmt: off
|
||||
y = 2
|
||||
# fmt: on
|
||||
@@ -1 +0,0 @@
|
||||
{"target_version": "3.14"}
|
||||
@@ -1,40 +0,0 @@
|
||||
x = t"foo"
|
||||
x = t'foo {{ {2 + 2}bar {{ baz'
|
||||
|
||||
x = t"foo {f'abc'} bar"
|
||||
|
||||
x = t"""foo {{ a
|
||||
foo {2 + 2}bar {{ baz
|
||||
|
||||
x = f"foo {{ {
|
||||
2 + 2 # comment
|
||||
}bar"
|
||||
|
||||
{{ baz
|
||||
|
||||
}} buzz
|
||||
|
||||
{print("abc" + "def"
|
||||
)}
|
||||
abc"""
|
||||
|
||||
t'{(abc:=10)}'
|
||||
|
||||
t'''This is a really long string, but just make sure that you reflow tstrings {
|
||||
2+2:d
|
||||
}'''
|
||||
t'This is a really long string, but just make sure that you reflow tstrings correctly {2+2:d}'
|
||||
|
||||
t"{ 2 + 2 = }"
|
||||
|
||||
t'{
|
||||
X
|
||||
!r
|
||||
}'
|
||||
|
||||
tr'\{{\}}'
|
||||
|
||||
t'''
|
||||
WITH {f'''
|
||||
{1}_cte AS ()'''}
|
||||
'''
|
||||
@@ -1,40 +0,0 @@
|
||||
x = t"foo"
|
||||
x = t"foo {{ {2 + 2}bar {{ baz"
|
||||
|
||||
x = t"foo {f'abc'} bar"
|
||||
|
||||
x = t"""foo {{ a
|
||||
foo {2 + 2}bar {{ baz
|
||||
|
||||
x = f"foo {{ {
|
||||
2 + 2 # comment
|
||||
}bar"
|
||||
|
||||
{{ baz
|
||||
|
||||
}} buzz
|
||||
|
||||
{print("abc" + "def"
|
||||
)}
|
||||
abc"""
|
||||
|
||||
t"{(abc:=10)}"
|
||||
|
||||
t"""This is a really long string, but just make sure that you reflow tstrings {
|
||||
2+2:d
|
||||
}"""
|
||||
t"This is a really long string, but just make sure that you reflow tstrings correctly {2+2:d}"
|
||||
|
||||
t"{ 2 + 2 = }"
|
||||
|
||||
t"{
|
||||
X
|
||||
!r
|
||||
}"
|
||||
|
||||
rt"\{{\}}"
|
||||
|
||||
t"""
|
||||
WITH {f'''
|
||||
{1}_cte AS ()'''}
|
||||
"""
|
||||
@@ -1 +0,0 @@
|
||||
{"preview": "enabled"}
|
||||
@@ -1,19 +0,0 @@
|
||||
# Regression test for https://github.com/psf/black/issues/3438
|
||||
|
||||
import ast
|
||||
import collections # fmt: skip
|
||||
import dataclasses
|
||||
# fmt: off
|
||||
import os
|
||||
# fmt: on
|
||||
import pathlib
|
||||
|
||||
import re # fmt: skip
|
||||
import secrets
|
||||
|
||||
# fmt: off
|
||||
import sys
|
||||
# fmt: on
|
||||
|
||||
import tempfile
|
||||
import zoneinfo
|
||||
@@ -1,19 +0,0 @@
|
||||
# Regression test for https://github.com/psf/black/issues/3438
|
||||
|
||||
import ast
|
||||
import collections # fmt: skip
|
||||
import dataclasses
|
||||
# fmt: off
|
||||
import os
|
||||
# fmt: on
|
||||
import pathlib
|
||||
|
||||
import re # fmt: skip
|
||||
import secrets
|
||||
|
||||
# fmt: off
|
||||
import sys
|
||||
# fmt: on
|
||||
|
||||
import tempfile
|
||||
import zoneinfo
|
||||
@@ -156,6 +156,24 @@ Please use `--build-option` instead,
|
||||
`--global-option` is reserved to flags like `--verbose` or `--quiet`.
|
||||
"""
|
||||
|
||||
this_will_become_one_line = (
|
||||
"a"
|
||||
"b"
|
||||
"c"
|
||||
)
|
||||
|
||||
this_will_stay_on_three_lines = (
|
||||
"a" # comment
|
||||
"b"
|
||||
"c"
|
||||
)
|
||||
|
||||
this_will_also_become_one_line = ( # comment
|
||||
"a"
|
||||
"b"
|
||||
"c"
|
||||
)
|
||||
|
||||
assert some_var == expected_result, """
|
||||
test
|
||||
"""
|
||||
|
||||
@@ -198,6 +198,16 @@ Please use `--build-option` instead,
|
||||
`--global-option` is reserved to flags like `--verbose` or `--quiet`.
|
||||
"""
|
||||
|
||||
this_will_become_one_line = "abc"
|
||||
|
||||
this_will_stay_on_three_lines = (
|
||||
"a" # comment
|
||||
"b"
|
||||
"c"
|
||||
)
|
||||
|
||||
this_will_also_become_one_line = "abc" # comment
|
||||
|
||||
assert some_var == expected_result, """
|
||||
test
|
||||
"""
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
{"preview": "enabled"}
|
||||
@@ -1,10 +0,0 @@
|
||||
def foo(
|
||||
a, #type:int
|
||||
b, #type: str
|
||||
c, # type: List[int]
|
||||
d, # type: Dict[int, str]
|
||||
e, # type: ignore
|
||||
f, # type : ignore
|
||||
g, # type : ignore
|
||||
):
|
||||
pass
|
||||
@@ -1,10 +0,0 @@
|
||||
def foo(
|
||||
a, # type: int
|
||||
b, # type: str
|
||||
c, # type: List[int]
|
||||
d, # type: Dict[int, str]
|
||||
e, # type: ignore
|
||||
f, # type : ignore
|
||||
g, # type : ignore
|
||||
):
|
||||
pass
|
||||
@@ -1 +0,0 @@
|
||||
{"preview": "enabled"}
|
||||
@@ -1,16 +0,0 @@
|
||||
# Remove unnecessary parentheses from LHS of assignments
|
||||
|
||||
|
||||
def a():
|
||||
return [1, 2, 3]
|
||||
|
||||
|
||||
# Single variable with unnecessary parentheses
|
||||
(b) = a()[0]
|
||||
|
||||
# Tuple unpacking with unnecessary parentheses
|
||||
(c, *_) = a()
|
||||
|
||||
# These should not be changed - parentheses are necessary
|
||||
(d,) = a() # single-element tuple
|
||||
e = (1 + 2) * 3 # RHS has precedence needs
|
||||
@@ -1,16 +0,0 @@
|
||||
# Remove unnecessary parentheses from LHS of assignments
|
||||
|
||||
|
||||
def a():
|
||||
return [1, 2, 3]
|
||||
|
||||
|
||||
# Single variable with unnecessary parentheses
|
||||
b = a()[0]
|
||||
|
||||
# Tuple unpacking with unnecessary parentheses
|
||||
c, *_ = a()
|
||||
|
||||
# These should not be changed - parentheses are necessary
|
||||
(d,) = a() # single-element tuple
|
||||
e = (1 + 2) * 3 # RHS has precedence needs
|
||||
@@ -1,5 +1,6 @@
|
||||
---
|
||||
source: crates/ruff_python_formatter/tests/fixtures.rs
|
||||
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/cases/fmtonoff.py
|
||||
---
|
||||
## Input
|
||||
|
||||
@@ -97,22 +98,20 @@ def example(session):
|
||||
.all()
|
||||
# fmt: on
|
||||
def off_and_on_without_data():
|
||||
"""Test that comment-only fmt:off/on blocks preserve formatting."""
|
||||
# fmt: off
|
||||
#should not be formatted
|
||||
# fmt: on
|
||||
"""All comments here are technically on the same prefix.
|
||||
|
||||
The comments between will be formatted. This is a known limitation.
|
||||
"""
|
||||
# fmt: off
|
||||
|
||||
#should not be formatted
|
||||
|
||||
# fmt: on
|
||||
# fmt: off
|
||||
#should not be formatted
|
||||
#should not be formatted #also should not be formatted
|
||||
#hey, that won't work
|
||||
|
||||
|
||||
# fmt: on
|
||||
pass
|
||||
def on_and_off_with_comment_only_blocks():
|
||||
"""Test that fmt:off/on works with multiple directives and comment-only blocks."""
|
||||
def on_and_off_broken():
|
||||
"""Another known limitation."""
|
||||
# fmt: on
|
||||
# fmt: off
|
||||
this=should.not_be.formatted()
|
||||
@@ -121,16 +120,7 @@ def on_and_off_with_comment_only_blocks():
|
||||
now . considers . multiple . fmt . directives . within . one . prefix
|
||||
# fmt: on
|
||||
# fmt: off
|
||||
#should not be formatted
|
||||
# fmt: on
|
||||
# fmt: off
|
||||
|
||||
#should not be formatted
|
||||
|
||||
# fmt: on
|
||||
# fmt: off
|
||||
#should not be formatted
|
||||
#should not be formatted #also should not be formatted
|
||||
# ...but comments still get reformatted even though they should not be
|
||||
# fmt: on
|
||||
def long_lines():
|
||||
if True:
|
||||
@@ -195,50 +185,6 @@ cfg.rule(
|
||||
# fmt: on
|
||||
xxxxxxxxxx_xxxxxxxxxxx_xxxxxxx_xxxxxxxxx=5
|
||||
)
|
||||
|
||||
# Test comment-only blocks at file level with various spacing patterns
|
||||
# fmt: off
|
||||
#nospace
|
||||
# twospaces
|
||||
# fmt: on
|
||||
|
||||
|
||||
# fmt: off
|
||||
#nospaceatall
|
||||
#extraspaces
|
||||
#evenmorespaces
|
||||
# fmt: on
|
||||
|
||||
|
||||
# fmt: off
|
||||
# fmt: on
|
||||
|
||||
|
||||
# fmt: off
|
||||
#SBATCH --job-name=test
|
||||
#SBATCH --output=test.out
|
||||
# fmt: on
|
||||
|
||||
|
||||
# fmt: off
|
||||
#first
|
||||
|
||||
#second
|
||||
# fmt: on
|
||||
|
||||
|
||||
# fmt: off
|
||||
#!@#$%^&*()
|
||||
#<=>+-*/
|
||||
# fmt: on
|
||||
|
||||
|
||||
# fmt: off
|
||||
#x=1+2
|
||||
#y = 3
|
||||
#z = 4
|
||||
# fmt: on
|
||||
|
||||
# fmt: off
|
||||
yield 'hello'
|
||||
# No formatting to the end of the file
|
||||
@@ -279,16 +225,28 @@ d={'a':1,
|
||||
# fmt: on
|
||||
goes + here,
|
||||
andhere,
|
||||
@@ -136,7 +137,7 @@
|
||||
and_=indeed . it is not formatted
|
||||
because . the . handling . inside . generate_ignored_nodes()
|
||||
now . considers . multiple . fmt . directives . within . one . prefix
|
||||
-
|
||||
+ # fmt: on
|
||||
@@ -118,8 +119,10 @@
|
||||
"""
|
||||
# fmt: off
|
||||
#should not be formatted
|
||||
|
||||
- # hey, that won't work
|
||||
|
||||
+ #hey, that won't work
|
||||
+
|
||||
+
|
||||
# fmt: on
|
||||
@@ -187,14 +188,18 @@
|
||||
pass
|
||||
|
||||
@@ -134,7 +137,7 @@
|
||||
now . considers . multiple . fmt . directives . within . one . prefix
|
||||
# fmt: on
|
||||
# fmt: off
|
||||
- # ...but comments still get reformatted even though they should not be
|
||||
+ # ...but comments still get reformatted even though they should not be
|
||||
# fmt: on
|
||||
|
||||
|
||||
@@ -174,14 +177,18 @@
|
||||
$
|
||||
""",
|
||||
# fmt: off
|
||||
@@ -429,24 +387,22 @@ def example(session):
|
||||
|
||||
|
||||
def off_and_on_without_data():
|
||||
"""Test that comment-only fmt:off/on blocks preserve formatting."""
|
||||
# fmt: off
|
||||
#should not be formatted
|
||||
# fmt: on
|
||||
"""All comments here are technically on the same prefix.
|
||||
|
||||
The comments between will be formatted. This is a known limitation.
|
||||
"""
|
||||
# fmt: off
|
||||
|
||||
#should not be formatted
|
||||
|
||||
# fmt: on
|
||||
# fmt: off
|
||||
#should not be formatted
|
||||
#should not be formatted #also should not be formatted
|
||||
#hey, that won't work
|
||||
|
||||
|
||||
# fmt: on
|
||||
pass
|
||||
|
||||
|
||||
def on_and_off_with_comment_only_blocks():
|
||||
"""Test that fmt:off/on works with multiple directives and comment-only blocks."""
|
||||
def on_and_off_broken():
|
||||
"""Another known limitation."""
|
||||
# fmt: on
|
||||
# fmt: off
|
||||
this=should.not_be.formatted()
|
||||
@@ -455,16 +411,7 @@ def on_and_off_with_comment_only_blocks():
|
||||
now . considers . multiple . fmt . directives . within . one . prefix
|
||||
# fmt: on
|
||||
# fmt: off
|
||||
#should not be formatted
|
||||
# fmt: on
|
||||
# fmt: off
|
||||
|
||||
#should not be formatted
|
||||
|
||||
# fmt: on
|
||||
# fmt: off
|
||||
#should not be formatted
|
||||
#should not be formatted #also should not be formatted
|
||||
# ...but comments still get reformatted even though they should not be
|
||||
# fmt: on
|
||||
|
||||
|
||||
@@ -545,50 +492,6 @@ cfg.rule(
|
||||
# fmt: on
|
||||
xxxxxxxxxx_xxxxxxxxxxx_xxxxxxx_xxxxxxxxx=5,
|
||||
)
|
||||
|
||||
# Test comment-only blocks at file level with various spacing patterns
|
||||
# fmt: off
|
||||
#nospace
|
||||
# twospaces
|
||||
# fmt: on
|
||||
|
||||
|
||||
# fmt: off
|
||||
#nospaceatall
|
||||
#extraspaces
|
||||
#evenmorespaces
|
||||
# fmt: on
|
||||
|
||||
|
||||
# fmt: off
|
||||
# fmt: on
|
||||
|
||||
|
||||
# fmt: off
|
||||
#SBATCH --job-name=test
|
||||
#SBATCH --output=test.out
|
||||
# fmt: on
|
||||
|
||||
|
||||
# fmt: off
|
||||
#first
|
||||
|
||||
#second
|
||||
# fmt: on
|
||||
|
||||
|
||||
# fmt: off
|
||||
#!@#$%^&*()
|
||||
#<=>+-*/
|
||||
# fmt: on
|
||||
|
||||
|
||||
# fmt: off
|
||||
#x=1+2
|
||||
#y = 3
|
||||
#z = 4
|
||||
# fmt: on
|
||||
|
||||
# fmt: off
|
||||
yield 'hello'
|
||||
# No formatting to the end of the file
|
||||
@@ -714,42 +617,29 @@ def example(session):
|
||||
|
||||
|
||||
def off_and_on_without_data():
|
||||
"""Test that comment-only fmt:off/on blocks preserve formatting."""
|
||||
# fmt: off
|
||||
#should not be formatted
|
||||
# fmt: on
|
||||
"""All comments here are technically on the same prefix.
|
||||
|
||||
The comments between will be formatted. This is a known limitation.
|
||||
"""
|
||||
# fmt: off
|
||||
|
||||
#should not be formatted
|
||||
# hey, that won't work
|
||||
|
||||
# fmt: on
|
||||
# fmt: off
|
||||
#should not be formatted
|
||||
#should not be formatted #also should not be formatted
|
||||
# fmt: on
|
||||
pass
|
||||
|
||||
|
||||
def on_and_off_with_comment_only_blocks():
|
||||
"""Test that fmt:off/on works with multiple directives and comment-only blocks."""
|
||||
def on_and_off_broken():
|
||||
"""Another known limitation."""
|
||||
# fmt: on
|
||||
# fmt: off
|
||||
this=should.not_be.formatted()
|
||||
and_=indeed . it is not formatted
|
||||
because . the . handling . inside . generate_ignored_nodes()
|
||||
now . considers . multiple . fmt . directives . within . one . prefix
|
||||
|
||||
# fmt: off
|
||||
#should not be formatted
|
||||
# fmt: on
|
||||
# fmt: off
|
||||
|
||||
#should not be formatted
|
||||
|
||||
# fmt: on
|
||||
# fmt: off
|
||||
#should not be formatted
|
||||
#should not be formatted #also should not be formatted
|
||||
# ...but comments still get reformatted even though they should not be
|
||||
# fmt: on
|
||||
|
||||
|
||||
@@ -826,50 +716,6 @@ cfg.rule(
|
||||
# fmt: on
|
||||
xxxxxxxxxx_xxxxxxxxxxx_xxxxxxx_xxxxxxxxx=5,
|
||||
)
|
||||
|
||||
# Test comment-only blocks at file level with various spacing patterns
|
||||
# fmt: off
|
||||
#nospace
|
||||
# twospaces
|
||||
# fmt: on
|
||||
|
||||
|
||||
# fmt: off
|
||||
#nospaceatall
|
||||
#extraspaces
|
||||
#evenmorespaces
|
||||
# fmt: on
|
||||
|
||||
|
||||
# fmt: off
|
||||
# fmt: on
|
||||
|
||||
|
||||
# fmt: off
|
||||
#SBATCH --job-name=test
|
||||
#SBATCH --output=test.out
|
||||
# fmt: on
|
||||
|
||||
|
||||
# fmt: off
|
||||
#first
|
||||
|
||||
#second
|
||||
# fmt: on
|
||||
|
||||
|
||||
# fmt: off
|
||||
#!@#$%^&*()
|
||||
#<=>+-*/
|
||||
# fmt: on
|
||||
|
||||
|
||||
# fmt: off
|
||||
#x=1+2
|
||||
#y = 3
|
||||
#z = 4
|
||||
# fmt: on
|
||||
|
||||
# fmt: off
|
||||
yield 'hello'
|
||||
# No formatting to the end of the file
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
---
|
||||
source: crates/ruff_python_formatter/tests/fixtures.rs
|
||||
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/cases/fmtskip10.py
|
||||
---
|
||||
## Input
|
||||
|
||||
@@ -7,24 +8,11 @@ source: crates/ruff_python_formatter/tests/fixtures.rs
|
||||
def foo(): return "mock" # fmt: skip
|
||||
if True: print("yay") # fmt: skip
|
||||
for i in range(10): print(i) # fmt: skip
|
||||
if True: print("this"); print("that") # fmt: skip
|
||||
while True: print("loop"); break # fmt: skip
|
||||
for x in [1, 2]: print(x); print("done") # fmt: skip
|
||||
def f(x: int): return x # fmt: skip
|
||||
|
||||
j = 1 # fmt: skip
|
||||
while j < 10: j += 1 # fmt: skip
|
||||
|
||||
b = [c for c in "A very long string that would normally generate some kind of collapse, since it is this long"] # fmt: skip
|
||||
|
||||
v = (
|
||||
foo_dict # fmt: skip
|
||||
.setdefault("a", {})
|
||||
.setdefault("b", {})
|
||||
.setdefault("c", {})
|
||||
.setdefault("d", {})
|
||||
.setdefault("e", {})
|
||||
)
|
||||
```
|
||||
|
||||
## Black Differences
|
||||
@@ -32,30 +20,19 @@ v = (
|
||||
```diff
|
||||
--- Black
|
||||
+++ Ruff
|
||||
@@ -1,15 +1,20 @@
|
||||
@@ -1,8 +1,10 @@
|
||||
def foo(): return "mock" # fmt: skip
|
||||
+
|
||||
+
|
||||
if True: print("yay") # fmt: skip
|
||||
for i in range(10): print(i) # fmt: skip
|
||||
if True: print("this"); print("that") # fmt: skip
|
||||
while True: print("loop"); break # fmt: skip
|
||||
for x in [1, 2]: print(x); print("done") # fmt: skip
|
||||
-def f(x: int): return x # fmt: skip
|
||||
|
||||
-j = 1 # fmt: skip
|
||||
+
|
||||
+def f(x: int): return x # fmt: skip
|
||||
+
|
||||
+
|
||||
+j = 1 # fmt: skip
|
||||
while j < 10: j += 1 # fmt: skip
|
||||
|
||||
-b = [c for c in "A very long string that would normally generate some kind of collapse, since it is this long"] # fmt: skip
|
||||
+b = [c for c in "A very long string that would normally generate some kind of collapse, since it is this long"] # fmt: skip
|
||||
|
||||
v = (
|
||||
foo_dict # fmt: skip
|
||||
```
|
||||
|
||||
## Ruff Output
|
||||
@@ -66,27 +43,11 @@ def foo(): return "mock" # fmt: skip
|
||||
|
||||
if True: print("yay") # fmt: skip
|
||||
for i in range(10): print(i) # fmt: skip
|
||||
if True: print("this"); print("that") # fmt: skip
|
||||
while True: print("loop"); break # fmt: skip
|
||||
for x in [1, 2]: print(x); print("done") # fmt: skip
|
||||
|
||||
|
||||
def f(x: int): return x # fmt: skip
|
||||
|
||||
|
||||
j = 1 # fmt: skip
|
||||
while j < 10: j += 1 # fmt: skip
|
||||
|
||||
b = [c for c in "A very long string that would normally generate some kind of collapse, since it is this long"] # fmt: skip
|
||||
|
||||
v = (
|
||||
foo_dict # fmt: skip
|
||||
.setdefault("a", {})
|
||||
.setdefault("b", {})
|
||||
.setdefault("c", {})
|
||||
.setdefault("d", {})
|
||||
.setdefault("e", {})
|
||||
)
|
||||
```
|
||||
|
||||
## Black Output
|
||||
@@ -95,22 +56,9 @@ v = (
|
||||
def foo(): return "mock" # fmt: skip
|
||||
if True: print("yay") # fmt: skip
|
||||
for i in range(10): print(i) # fmt: skip
|
||||
if True: print("this"); print("that") # fmt: skip
|
||||
while True: print("loop"); break # fmt: skip
|
||||
for x in [1, 2]: print(x); print("done") # fmt: skip
|
||||
def f(x: int): return x # fmt: skip
|
||||
|
||||
j = 1 # fmt: skip
|
||||
while j < 10: j += 1 # fmt: skip
|
||||
|
||||
b = [c for c in "A very long string that would normally generate some kind of collapse, since it is this long"] # fmt: skip
|
||||
|
||||
v = (
|
||||
foo_dict # fmt: skip
|
||||
.setdefault("a", {})
|
||||
.setdefault("b", {})
|
||||
.setdefault("c", {})
|
||||
.setdefault("d", {})
|
||||
.setdefault("e", {})
|
||||
)
|
||||
```
|
||||
|
||||
@@ -1,321 +0,0 @@
|
||||
---
|
||||
source: crates/ruff_python_formatter/tests/fixtures.rs
|
||||
---
|
||||
## Input
|
||||
|
||||
```python
|
||||
def foo():
|
||||
pass
|
||||
|
||||
|
||||
# comment 1 # fmt: skip
|
||||
# comment 2
|
||||
|
||||
[
|
||||
(1, 2),
|
||||
# # fmt: off
|
||||
# (3,
|
||||
# 4),
|
||||
# # fmt: on
|
||||
(5, 6),
|
||||
]
|
||||
|
||||
[
|
||||
(1, 2),
|
||||
# # fmt: off
|
||||
# (3,
|
||||
# 4),
|
||||
# fmt: on
|
||||
(5, 6),
|
||||
]
|
||||
|
||||
|
||||
[
|
||||
(1, 2),
|
||||
# fmt: off
|
||||
# (3,
|
||||
# 4),
|
||||
# # fmt: on
|
||||
(5, 6),
|
||||
]
|
||||
|
||||
|
||||
[
|
||||
(1, 2),
|
||||
# fmt: off
|
||||
# (3,
|
||||
# 4),
|
||||
# fmt: on
|
||||
(5, 6),
|
||||
]
|
||||
|
||||
[
|
||||
(1, 2),
|
||||
# # fmt: off
|
||||
(3,
|
||||
4),
|
||||
# # fmt: on
|
||||
(5, 6),
|
||||
]
|
||||
|
||||
[
|
||||
(1, 2),
|
||||
# # fmt: off
|
||||
(3,
|
||||
4),
|
||||
# fmt: on
|
||||
(5, 6),
|
||||
]
|
||||
|
||||
|
||||
[
|
||||
(1, 2),
|
||||
# fmt: off
|
||||
(3,
|
||||
4),
|
||||
# # fmt: on
|
||||
(5, 6),
|
||||
]
|
||||
|
||||
|
||||
[
|
||||
(1, 2),
|
||||
# fmt: off
|
||||
(3,
|
||||
4),
|
||||
# fmt: on
|
||||
(5, 6),
|
||||
]
|
||||
|
||||
|
||||
if False:
|
||||
# fmt: off # some other comment
|
||||
pass
|
||||
```
|
||||
|
||||
## Black Differences
|
||||
|
||||
```diff
|
||||
--- Black
|
||||
+++ Ruff
|
||||
@@ -46,8 +46,7 @@
|
||||
[
|
||||
(1, 2),
|
||||
# # fmt: off
|
||||
- (3,
|
||||
- 4),
|
||||
+ (3, 4),
|
||||
# # fmt: on
|
||||
(5, 6),
|
||||
]
|
||||
@@ -55,8 +54,7 @@
|
||||
[
|
||||
(1, 2),
|
||||
# # fmt: off
|
||||
- (3,
|
||||
- 4),
|
||||
+ (3, 4),
|
||||
# fmt: on
|
||||
(5, 6),
|
||||
]
|
||||
@@ -65,8 +63,7 @@
|
||||
[
|
||||
(1, 2),
|
||||
# fmt: off
|
||||
- (3,
|
||||
- 4),
|
||||
+ (3, 4),
|
||||
# # fmt: on
|
||||
(5, 6),
|
||||
]
|
||||
@@ -75,8 +72,7 @@
|
||||
[
|
||||
(1, 2),
|
||||
# fmt: off
|
||||
- (3,
|
||||
- 4),
|
||||
+ (3, 4),
|
||||
# fmt: on
|
||||
(5, 6),
|
||||
]
|
||||
```
|
||||
|
||||
## Ruff Output
|
||||
|
||||
```python
|
||||
def foo():
|
||||
pass
|
||||
|
||||
|
||||
# comment 1 # fmt: skip
|
||||
# comment 2
|
||||
|
||||
[
|
||||
(1, 2),
|
||||
# # fmt: off
|
||||
# (3,
|
||||
# 4),
|
||||
# # fmt: on
|
||||
(5, 6),
|
||||
]
|
||||
|
||||
[
|
||||
(1, 2),
|
||||
# # fmt: off
|
||||
# (3,
|
||||
# 4),
|
||||
# fmt: on
|
||||
(5, 6),
|
||||
]
|
||||
|
||||
|
||||
[
|
||||
(1, 2),
|
||||
# fmt: off
|
||||
# (3,
|
||||
# 4),
|
||||
# # fmt: on
|
||||
(5, 6),
|
||||
]
|
||||
|
||||
|
||||
[
|
||||
(1, 2),
|
||||
# fmt: off
|
||||
# (3,
|
||||
# 4),
|
||||
# fmt: on
|
||||
(5, 6),
|
||||
]
|
||||
|
||||
[
|
||||
(1, 2),
|
||||
# # fmt: off
|
||||
(3, 4),
|
||||
# # fmt: on
|
||||
(5, 6),
|
||||
]
|
||||
|
||||
[
|
||||
(1, 2),
|
||||
# # fmt: off
|
||||
(3, 4),
|
||||
# fmt: on
|
||||
(5, 6),
|
||||
]
|
||||
|
||||
|
||||
[
|
||||
(1, 2),
|
||||
# fmt: off
|
||||
(3, 4),
|
||||
# # fmt: on
|
||||
(5, 6),
|
||||
]
|
||||
|
||||
|
||||
[
|
||||
(1, 2),
|
||||
# fmt: off
|
||||
(3, 4),
|
||||
# fmt: on
|
||||
(5, 6),
|
||||
]
|
||||
|
||||
|
||||
if False:
|
||||
# fmt: off # some other comment
|
||||
pass
|
||||
```
|
||||
|
||||
## Black Output
|
||||
|
||||
```python
|
||||
def foo():
|
||||
pass
|
||||
|
||||
|
||||
# comment 1 # fmt: skip
|
||||
# comment 2
|
||||
|
||||
[
|
||||
(1, 2),
|
||||
# # fmt: off
|
||||
# (3,
|
||||
# 4),
|
||||
# # fmt: on
|
||||
(5, 6),
|
||||
]
|
||||
|
||||
[
|
||||
(1, 2),
|
||||
# # fmt: off
|
||||
# (3,
|
||||
# 4),
|
||||
# fmt: on
|
||||
(5, 6),
|
||||
]
|
||||
|
||||
|
||||
[
|
||||
(1, 2),
|
||||
# fmt: off
|
||||
# (3,
|
||||
# 4),
|
||||
# # fmt: on
|
||||
(5, 6),
|
||||
]
|
||||
|
||||
|
||||
[
|
||||
(1, 2),
|
||||
# fmt: off
|
||||
# (3,
|
||||
# 4),
|
||||
# fmt: on
|
||||
(5, 6),
|
||||
]
|
||||
|
||||
[
|
||||
(1, 2),
|
||||
# # fmt: off
|
||||
(3,
|
||||
4),
|
||||
# # fmt: on
|
||||
(5, 6),
|
||||
]
|
||||
|
||||
[
|
||||
(1, 2),
|
||||
# # fmt: off
|
||||
(3,
|
||||
4),
|
||||
# fmt: on
|
||||
(5, 6),
|
||||
]
|
||||
|
||||
|
||||
[
|
||||
(1, 2),
|
||||
# fmt: off
|
||||
(3,
|
||||
4),
|
||||
# # fmt: on
|
||||
(5, 6),
|
||||
]
|
||||
|
||||
|
||||
[
|
||||
(1, 2),
|
||||
# fmt: off
|
||||
(3,
|
||||
4),
|
||||
# fmt: on
|
||||
(5, 6),
|
||||
]
|
||||
|
||||
|
||||
if False:
|
||||
# fmt: off # some other comment
|
||||
pass
|
||||
```
|
||||
@@ -1,59 +0,0 @@
|
||||
---
|
||||
source: crates/ruff_python_formatter/tests/fixtures.rs
|
||||
---
|
||||
## Input
|
||||
|
||||
```python
|
||||
with open("file.txt") as f: content = f.read() # fmt: skip
|
||||
|
||||
# Ideally, only the last line would be ignored
|
||||
# But ignoring only part of the asexpr_test causes a parse error
|
||||
# Same with ignoring the asexpr_test without also ignoring the entire with_stmt
|
||||
with open (
|
||||
"file.txt" ,
|
||||
) as f: content = f.read() # fmt: skip
|
||||
```
|
||||
|
||||
## Black Differences
|
||||
|
||||
```diff
|
||||
--- Black
|
||||
+++ Ruff
|
||||
@@ -1,8 +1,8 @@
|
||||
-with open("file.txt") as f: content = f.read() # fmt: skip
|
||||
+with open("file.txt") as f: content = f.read() # fmt: skip
|
||||
|
||||
# Ideally, only the last line would be ignored
|
||||
# But ignoring only part of the asexpr_test causes a parse error
|
||||
# Same with ignoring the asexpr_test without also ignoring the entire with_stmt
|
||||
with open (
|
||||
"file.txt" ,
|
||||
-) as f: content = f.read() # fmt: skip
|
||||
+) as f: content = f.read() # fmt: skip
|
||||
```
|
||||
|
||||
## Ruff Output
|
||||
|
||||
```python
|
||||
with open("file.txt") as f: content = f.read() # fmt: skip
|
||||
|
||||
# Ideally, only the last line would be ignored
|
||||
# But ignoring only part of the asexpr_test causes a parse error
|
||||
# Same with ignoring the asexpr_test without also ignoring the entire with_stmt
|
||||
with open (
|
||||
"file.txt" ,
|
||||
) as f: content = f.read() # fmt: skip
|
||||
```
|
||||
|
||||
## Black Output
|
||||
|
||||
```python
|
||||
with open("file.txt") as f: content = f.read() # fmt: skip
|
||||
|
||||
# Ideally, only the last line would be ignored
|
||||
# But ignoring only part of the asexpr_test causes a parse error
|
||||
# Same with ignoring the asexpr_test without also ignoring the entire with_stmt
|
||||
with open (
|
||||
"file.txt" ,
|
||||
) as f: content = f.read() # fmt: skip
|
||||
```
|
||||
@@ -1,149 +0,0 @@
|
||||
---
|
||||
source: crates/ruff_python_formatter/tests/fixtures.rs
|
||||
---
|
||||
## Input
|
||||
|
||||
```python
|
||||
t = (
|
||||
{"foo": "very long string", "bar": "another very long string", "baz": "we should run out of space by now"}, # fmt: skip
|
||||
{"foo": "bar"},
|
||||
)
|
||||
|
||||
t = (
|
||||
{
|
||||
"foo": "very long string",
|
||||
"bar": "another very long string",
|
||||
"baz": "we should run out of space by now",
|
||||
}, # fmt: skip
|
||||
{"foo": "bar"},
|
||||
)
|
||||
|
||||
|
||||
t = (
|
||||
{"foo": "very long string", "bar": "another very long string", "baz": "we should run out of space by now"}, # fmt: skip
|
||||
{"foo": "bar",},
|
||||
)
|
||||
|
||||
t = (
|
||||
{
|
||||
"foo": "very long string",
|
||||
"bar": "another very long string",
|
||||
"baz": "we should run out of space by now",
|
||||
}, # fmt: skip
|
||||
{"foo": "bar",},
|
||||
)
|
||||
```
|
||||
|
||||
## Black Differences
|
||||
|
||||
```diff
|
||||
--- Black
|
||||
+++ Ruff
|
||||
@@ -1,5 +1,9 @@
|
||||
t = (
|
||||
- {"foo": "very long string", "bar": "another very long string", "baz": "we should run out of space by now"}, # fmt: skip
|
||||
+ {
|
||||
+ "foo": "very long string",
|
||||
+ "bar": "another very long string",
|
||||
+ "baz": "we should run out of space by now",
|
||||
+ }, # fmt: skip
|
||||
{"foo": "bar"},
|
||||
)
|
||||
|
||||
@@ -14,8 +18,12 @@
|
||||
|
||||
|
||||
t = (
|
||||
- {"foo": "very long string", "bar": "another very long string", "baz": "we should run out of space by now"}, # fmt: skip
|
||||
{
|
||||
+ "foo": "very long string",
|
||||
+ "bar": "another very long string",
|
||||
+ "baz": "we should run out of space by now",
|
||||
+ }, # fmt: skip
|
||||
+ {
|
||||
"foo": "bar",
|
||||
},
|
||||
)
|
||||
```
|
||||
|
||||
## Ruff Output
|
||||
|
||||
```python
|
||||
t = (
|
||||
{
|
||||
"foo": "very long string",
|
||||
"bar": "another very long string",
|
||||
"baz": "we should run out of space by now",
|
||||
}, # fmt: skip
|
||||
{"foo": "bar"},
|
||||
)
|
||||
|
||||
t = (
|
||||
{
|
||||
"foo": "very long string",
|
||||
"bar": "another very long string",
|
||||
"baz": "we should run out of space by now",
|
||||
}, # fmt: skip
|
||||
{"foo": "bar"},
|
||||
)
|
||||
|
||||
|
||||
t = (
|
||||
{
|
||||
"foo": "very long string",
|
||||
"bar": "another very long string",
|
||||
"baz": "we should run out of space by now",
|
||||
}, # fmt: skip
|
||||
{
|
||||
"foo": "bar",
|
||||
},
|
||||
)
|
||||
|
||||
t = (
|
||||
{
|
||||
"foo": "very long string",
|
||||
"bar": "another very long string",
|
||||
"baz": "we should run out of space by now",
|
||||
}, # fmt: skip
|
||||
{
|
||||
"foo": "bar",
|
||||
},
|
||||
)
|
||||
```
|
||||
|
||||
## Black Output
|
||||
|
||||
```python
|
||||
t = (
|
||||
{"foo": "very long string", "bar": "another very long string", "baz": "we should run out of space by now"}, # fmt: skip
|
||||
{"foo": "bar"},
|
||||
)
|
||||
|
||||
t = (
|
||||
{
|
||||
"foo": "very long string",
|
||||
"bar": "another very long string",
|
||||
"baz": "we should run out of space by now",
|
||||
}, # fmt: skip
|
||||
{"foo": "bar"},
|
||||
)
|
||||
|
||||
|
||||
t = (
|
||||
{"foo": "very long string", "bar": "another very long string", "baz": "we should run out of space by now"}, # fmt: skip
|
||||
{
|
||||
"foo": "bar",
|
||||
},
|
||||
)
|
||||
|
||||
t = (
|
||||
{
|
||||
"foo": "very long string",
|
||||
"bar": "another very long string",
|
||||
"baz": "we should run out of space by now",
|
||||
}, # fmt: skip
|
||||
{
|
||||
"foo": "bar",
|
||||
},
|
||||
)
|
||||
```
|
||||
@@ -1,43 +0,0 @@
|
||||
---
|
||||
source: crates/ruff_python_formatter/tests/fixtures.rs
|
||||
---
|
||||
## Input
|
||||
|
||||
```python
|
||||
a = "this is some code"
|
||||
b = 5 # fmt:skip
|
||||
c = 9 #fmt: skip
|
||||
d = "thisisasuperlongstringthisisasuperlongstringthisisasuperlongstringthisisasuperlongstring" # fmt:skip
|
||||
```
|
||||
|
||||
## Black Differences
|
||||
|
||||
```diff
|
||||
--- Black
|
||||
+++ Ruff
|
||||
@@ -1,4 +1,4 @@
|
||||
a = "this is some code"
|
||||
-b = 5 # fmt:skip
|
||||
-c = 9 #fmt: skip
|
||||
+b = 5 # fmt:skip
|
||||
+c = 9 # fmt: skip
|
||||
d = "thisisasuperlongstringthisisasuperlongstringthisisasuperlongstringthisisasuperlongstring" # fmt:skip
|
||||
```
|
||||
|
||||
## Ruff Output
|
||||
|
||||
```python
|
||||
a = "this is some code"
|
||||
b = 5 # fmt:skip
|
||||
c = 9 # fmt: skip
|
||||
d = "thisisasuperlongstringthisisasuperlongstringthisisasuperlongstringthisisasuperlongstring" # fmt:skip
|
||||
```
|
||||
|
||||
## Black Output
|
||||
|
||||
```python
|
||||
a = "this is some code"
|
||||
b = 5 # fmt:skip
|
||||
c = 9 #fmt: skip
|
||||
d = "thisisasuperlongstringthisisasuperlongstringthisisasuperlongstringthisisasuperlongstring" # fmt:skip
|
||||
```
|
||||
@@ -1,98 +0,0 @@
|
||||
---
|
||||
source: crates/ruff_python_formatter/tests/fixtures.rs
|
||||
---
|
||||
## Input
|
||||
|
||||
```python
|
||||
# Multiple fmt: skip in multi-part if-clause
|
||||
class ClassWithALongName:
|
||||
Constant1 = 1
|
||||
Constant2 = 2
|
||||
Constant3 = 3
|
||||
|
||||
|
||||
def test():
|
||||
if (
|
||||
"cond1" == "cond1"
|
||||
and "cond2" == "cond2"
|
||||
and 1 in (
|
||||
ClassWithALongName.Constant1,
|
||||
ClassWithALongName.Constant2,
|
||||
ClassWithALongName.Constant3, # fmt: skip
|
||||
) # fmt: skip
|
||||
):
|
||||
return True
|
||||
return False
|
||||
```
|
||||
|
||||
## Black Differences
|
||||
|
||||
```diff
|
||||
--- Black
|
||||
+++ Ruff
|
||||
@@ -9,11 +9,12 @@
|
||||
if (
|
||||
"cond1" == "cond1"
|
||||
and "cond2" == "cond2"
|
||||
- and 1 in (
|
||||
+ and 1
|
||||
+ in (
|
||||
ClassWithALongName.Constant1,
|
||||
ClassWithALongName.Constant2,
|
||||
- ClassWithALongName.Constant3, # fmt: skip
|
||||
- ) # fmt: skip
|
||||
+ ClassWithALongName.Constant3, # fmt: skip
|
||||
+ ) # fmt: skip
|
||||
):
|
||||
return True
|
||||
return False
|
||||
```
|
||||
|
||||
## Ruff Output
|
||||
|
||||
```python
|
||||
# Multiple fmt: skip in multi-part if-clause
|
||||
class ClassWithALongName:
|
||||
Constant1 = 1
|
||||
Constant2 = 2
|
||||
Constant3 = 3
|
||||
|
||||
|
||||
def test():
|
||||
if (
|
||||
"cond1" == "cond1"
|
||||
and "cond2" == "cond2"
|
||||
and 1
|
||||
in (
|
||||
ClassWithALongName.Constant1,
|
||||
ClassWithALongName.Constant2,
|
||||
ClassWithALongName.Constant3, # fmt: skip
|
||||
) # fmt: skip
|
||||
):
|
||||
return True
|
||||
return False
|
||||
```
|
||||
|
||||
## Black Output
|
||||
|
||||
```python
|
||||
# Multiple fmt: skip in multi-part if-clause
|
||||
class ClassWithALongName:
|
||||
Constant1 = 1
|
||||
Constant2 = 2
|
||||
Constant3 = 3
|
||||
|
||||
|
||||
def test():
|
||||
if (
|
||||
"cond1" == "cond1"
|
||||
and "cond2" == "cond2"
|
||||
and 1 in (
|
||||
ClassWithALongName.Constant1,
|
||||
ClassWithALongName.Constant2,
|
||||
ClassWithALongName.Constant3, # fmt: skip
|
||||
) # fmt: skip
|
||||
):
|
||||
return True
|
||||
return False
|
||||
```
|
||||
@@ -1,148 +0,0 @@
|
||||
---
|
||||
source: crates/ruff_python_formatter/tests/fixtures.rs
|
||||
---
|
||||
## Input
|
||||
|
||||
```python
|
||||
# Multiple fmt: skip on string literals
|
||||
a = (
|
||||
"this should " # fmt: skip
|
||||
"be fine"
|
||||
)
|
||||
|
||||
b = (
|
||||
"this is " # fmt: skip
|
||||
"not working" # fmt: skip
|
||||
)
|
||||
|
||||
c = (
|
||||
"and neither " # fmt: skip
|
||||
"is this " # fmt: skip
|
||||
"working"
|
||||
)
|
||||
|
||||
d = (
|
||||
"nor "
|
||||
"is this " # fmt: skip
|
||||
"working" # fmt: skip
|
||||
)
|
||||
|
||||
e = (
|
||||
"and this " # fmt: skip
|
||||
"is definitely "
|
||||
"not working" # fmt: skip
|
||||
)
|
||||
|
||||
# Dictionary entries with fmt: skip (covers issue with long lines)
|
||||
hotkeys = {
|
||||
"editor:swap-line-down": [{"key": "ArrowDown", "modifiers": ["Alt", "Mod"]}], # fmt: skip
|
||||
"editor:swap-line-up": [{"key": "ArrowUp", "modifiers": ["Alt", "Mod"]}], # fmt: skip
|
||||
"editor:toggle-source": [{"key": "S", "modifiers": ["Alt", "Mod"]}], # fmt: skip
|
||||
}
|
||||
```
|
||||
|
||||
## Black Differences
|
||||
|
||||
```diff
|
||||
--- Black
|
||||
+++ Ruff
|
||||
@@ -29,7 +29,11 @@
|
||||
|
||||
# Dictionary entries with fmt: skip (covers issue with long lines)
|
||||
hotkeys = {
|
||||
- "editor:swap-line-down": [{"key": "ArrowDown", "modifiers": ["Alt", "Mod"]}], # fmt: skip
|
||||
- "editor:swap-line-up": [{"key": "ArrowUp", "modifiers": ["Alt", "Mod"]}], # fmt: skip
|
||||
- "editor:toggle-source": [{"key": "S", "modifiers": ["Alt", "Mod"]}], # fmt: skip
|
||||
+ "editor:swap-line-down": [
|
||||
+ {"key": "ArrowDown", "modifiers": ["Alt", "Mod"]}
|
||||
+ ], # fmt: skip
|
||||
+ "editor:swap-line-up": [
|
||||
+ {"key": "ArrowUp", "modifiers": ["Alt", "Mod"]}
|
||||
+ ], # fmt: skip
|
||||
+ "editor:toggle-source": [{"key": "S", "modifiers": ["Alt", "Mod"]}], # fmt: skip
|
||||
}
|
||||
```
|
||||
|
||||
## Ruff Output
|
||||
|
||||
```python
|
||||
# Multiple fmt: skip on string literals
|
||||
a = (
|
||||
"this should " # fmt: skip
|
||||
"be fine"
|
||||
)
|
||||
|
||||
b = (
|
||||
"this is " # fmt: skip
|
||||
"not working" # fmt: skip
|
||||
)
|
||||
|
||||
c = (
|
||||
"and neither " # fmt: skip
|
||||
"is this " # fmt: skip
|
||||
"working"
|
||||
)
|
||||
|
||||
d = (
|
||||
"nor "
|
||||
"is this " # fmt: skip
|
||||
"working" # fmt: skip
|
||||
)
|
||||
|
||||
e = (
|
||||
"and this " # fmt: skip
|
||||
"is definitely "
|
||||
"not working" # fmt: skip
|
||||
)
|
||||
|
||||
# Dictionary entries with fmt: skip (covers issue with long lines)
|
||||
hotkeys = {
|
||||
"editor:swap-line-down": [
|
||||
{"key": "ArrowDown", "modifiers": ["Alt", "Mod"]}
|
||||
], # fmt: skip
|
||||
"editor:swap-line-up": [
|
||||
{"key": "ArrowUp", "modifiers": ["Alt", "Mod"]}
|
||||
], # fmt: skip
|
||||
"editor:toggle-source": [{"key": "S", "modifiers": ["Alt", "Mod"]}], # fmt: skip
|
||||
}
|
||||
```
|
||||
|
||||
## Black Output
|
||||
|
||||
```python
|
||||
# Multiple fmt: skip on string literals
|
||||
a = (
|
||||
"this should " # fmt: skip
|
||||
"be fine"
|
||||
)
|
||||
|
||||
b = (
|
||||
"this is " # fmt: skip
|
||||
"not working" # fmt: skip
|
||||
)
|
||||
|
||||
c = (
|
||||
"and neither " # fmt: skip
|
||||
"is this " # fmt: skip
|
||||
"working"
|
||||
)
|
||||
|
||||
d = (
|
||||
"nor "
|
||||
"is this " # fmt: skip
|
||||
"working" # fmt: skip
|
||||
)
|
||||
|
||||
e = (
|
||||
"and this " # fmt: skip
|
||||
"is definitely "
|
||||
"not working" # fmt: skip
|
||||
)
|
||||
|
||||
# Dictionary entries with fmt: skip (covers issue with long lines)
|
||||
hotkeys = {
|
||||
"editor:swap-line-down": [{"key": "ArrowDown", "modifiers": ["Alt", "Mod"]}], # fmt: skip
|
||||
"editor:swap-line-up": [{"key": "ArrowUp", "modifiers": ["Alt", "Mod"]}], # fmt: skip
|
||||
"editor:toggle-source": [{"key": "S", "modifiers": ["Alt", "Mod"]}], # fmt: skip
|
||||
}
|
||||
```
|
||||
@@ -1,188 +0,0 @@
|
||||
---
|
||||
source: crates/ruff_python_formatter/tests/fixtures.rs
|
||||
---
|
||||
## Input
|
||||
|
||||
```python
|
||||
x = t"foo"
|
||||
x = t'foo {{ {2 + 2}bar {{ baz'
|
||||
|
||||
x = t"foo {f'abc'} bar"
|
||||
|
||||
x = t"""foo {{ a
|
||||
foo {2 + 2}bar {{ baz
|
||||
|
||||
x = f"foo {{ {
|
||||
2 + 2 # comment
|
||||
}bar"
|
||||
|
||||
{{ baz
|
||||
|
||||
}} buzz
|
||||
|
||||
{print("abc" + "def"
|
||||
)}
|
||||
abc"""
|
||||
|
||||
t'{(abc:=10)}'
|
||||
|
||||
t'''This is a really long string, but just make sure that you reflow tstrings {
|
||||
2+2:d
|
||||
}'''
|
||||
t'This is a really long string, but just make sure that you reflow tstrings correctly {2+2:d}'
|
||||
|
||||
t"{ 2 + 2 = }"
|
||||
|
||||
t'{
|
||||
X
|
||||
!r
|
||||
}'
|
||||
|
||||
tr'\{{\}}'
|
||||
|
||||
t'''
|
||||
WITH {f'''
|
||||
{1}_cte AS ()'''}
|
||||
'''
|
||||
```
|
||||
|
||||
## Black Differences
|
||||
|
||||
```diff
|
||||
--- Black
|
||||
+++ Ruff
|
||||
@@ -7,34 +7,32 @@
|
||||
foo {2 + 2}bar {{ baz
|
||||
|
||||
x = f"foo {{ {
|
||||
- 2 + 2 # comment
|
||||
- }bar"
|
||||
+ 2 + 2 # comment
|
||||
+}bar"
|
||||
|
||||
{{ baz
|
||||
|
||||
}} buzz
|
||||
|
||||
- {print("abc" + "def"
|
||||
-)}
|
||||
+ {print("abc" + "def")}
|
||||
abc"""
|
||||
|
||||
-t"{(abc:=10)}"
|
||||
+t"{(abc := 10)}"
|
||||
|
||||
t"""This is a really long string, but just make sure that you reflow tstrings {
|
||||
- 2+2:d
|
||||
+ 2 + 2:d
|
||||
}"""
|
||||
-t"This is a really long string, but just make sure that you reflow tstrings correctly {2+2:d}"
|
||||
+t"This is a really long string, but just make sure that you reflow tstrings correctly {2 + 2:d}"
|
||||
|
||||
t"{ 2 + 2 = }"
|
||||
|
||||
-t"{
|
||||
-X
|
||||
-!r
|
||||
-}"
|
||||
+t"{X!r}"
|
||||
|
||||
rt"\{{\}}"
|
||||
|
||||
t"""
|
||||
- WITH {f'''
|
||||
- {1}_cte AS ()'''}
|
||||
+ WITH {
|
||||
+ f'''
|
||||
+ {1}_cte AS ()'''
|
||||
+}
|
||||
"""
|
||||
```
|
||||
|
||||
## Ruff Output
|
||||
|
||||
```python
|
||||
x = t"foo"
|
||||
x = t"foo {{ {2 + 2}bar {{ baz"
|
||||
|
||||
x = t"foo {f'abc'} bar"
|
||||
|
||||
x = t"""foo {{ a
|
||||
foo {2 + 2}bar {{ baz
|
||||
|
||||
x = f"foo {{ {
|
||||
2 + 2 # comment
|
||||
}bar"
|
||||
|
||||
{{ baz
|
||||
|
||||
}} buzz
|
||||
|
||||
{print("abc" + "def")}
|
||||
abc"""
|
||||
|
||||
t"{(abc := 10)}"
|
||||
|
||||
t"""This is a really long string, but just make sure that you reflow tstrings {
|
||||
2 + 2:d
|
||||
}"""
|
||||
t"This is a really long string, but just make sure that you reflow tstrings correctly {2 + 2:d}"
|
||||
|
||||
t"{ 2 + 2 = }"
|
||||
|
||||
t"{X!r}"
|
||||
|
||||
rt"\{{\}}"
|
||||
|
||||
t"""
|
||||
WITH {
|
||||
f'''
|
||||
{1}_cte AS ()'''
|
||||
}
|
||||
"""
|
||||
```
|
||||
|
||||
## Black Output
|
||||
|
||||
```python
|
||||
x = t"foo"
|
||||
x = t"foo {{ {2 + 2}bar {{ baz"
|
||||
|
||||
x = t"foo {f'abc'} bar"
|
||||
|
||||
x = t"""foo {{ a
|
||||
foo {2 + 2}bar {{ baz
|
||||
|
||||
x = f"foo {{ {
|
||||
2 + 2 # comment
|
||||
}bar"
|
||||
|
||||
{{ baz
|
||||
|
||||
}} buzz
|
||||
|
||||
{print("abc" + "def"
|
||||
)}
|
||||
abc"""
|
||||
|
||||
t"{(abc:=10)}"
|
||||
|
||||
t"""This is a really long string, but just make sure that you reflow tstrings {
|
||||
2+2:d
|
||||
}"""
|
||||
t"This is a really long string, but just make sure that you reflow tstrings correctly {2+2:d}"
|
||||
|
||||
t"{ 2 + 2 = }"
|
||||
|
||||
t"{
|
||||
X
|
||||
!r
|
||||
}"
|
||||
|
||||
rt"\{{\}}"
|
||||
|
||||
t"""
|
||||
WITH {f'''
|
||||
{1}_cte AS ()'''}
|
||||
"""
|
||||
```
|
||||
@@ -1,90 +0,0 @@
|
||||
---
|
||||
source: crates/ruff_python_formatter/tests/fixtures.rs
|
||||
---
|
||||
## Input
|
||||
|
||||
```python
|
||||
# Regression test for https://github.com/psf/black/issues/3438
|
||||
|
||||
import ast
|
||||
import collections # fmt: skip
|
||||
import dataclasses
|
||||
# fmt: off
|
||||
import os
|
||||
# fmt: on
|
||||
import pathlib
|
||||
|
||||
import re # fmt: skip
|
||||
import secrets
|
||||
|
||||
# fmt: off
|
||||
import sys
|
||||
# fmt: on
|
||||
|
||||
import tempfile
|
||||
import zoneinfo
|
||||
```
|
||||
|
||||
## Black Differences
|
||||
|
||||
```diff
|
||||
--- Black
|
||||
+++ Ruff
|
||||
@@ -3,6 +3,7 @@
|
||||
import ast
|
||||
import collections # fmt: skip
|
||||
import dataclasses
|
||||
+
|
||||
# fmt: off
|
||||
import os
|
||||
# fmt: on
|
||||
```
|
||||
|
||||
## Ruff Output
|
||||
|
||||
```python
|
||||
# Regression test for https://github.com/psf/black/issues/3438
|
||||
|
||||
import ast
|
||||
import collections # fmt: skip
|
||||
import dataclasses
|
||||
|
||||
# fmt: off
|
||||
import os
|
||||
# fmt: on
|
||||
import pathlib
|
||||
|
||||
import re # fmt: skip
|
||||
import secrets
|
||||
|
||||
# fmt: off
|
||||
import sys
|
||||
# fmt: on
|
||||
|
||||
import tempfile
|
||||
import zoneinfo
|
||||
```
|
||||
|
||||
## Black Output
|
||||
|
||||
```python
|
||||
# Regression test for https://github.com/psf/black/issues/3438
|
||||
|
||||
import ast
|
||||
import collections # fmt: skip
|
||||
import dataclasses
|
||||
# fmt: off
|
||||
import os
|
||||
# fmt: on
|
||||
import pathlib
|
||||
|
||||
import re # fmt: skip
|
||||
import secrets
|
||||
|
||||
# fmt: off
|
||||
import sys
|
||||
# fmt: on
|
||||
|
||||
import tempfile
|
||||
import zoneinfo
|
||||
```
|
||||
@@ -1,5 +1,6 @@
|
||||
---
|
||||
source: crates/ruff_python_formatter/tests/fixtures.rs
|
||||
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_multiline_strings.py
|
||||
---
|
||||
## Input
|
||||
|
||||
@@ -162,6 +163,24 @@ Please use `--build-option` instead,
|
||||
`--global-option` is reserved to flags like `--verbose` or `--quiet`.
|
||||
"""
|
||||
|
||||
this_will_become_one_line = (
|
||||
"a"
|
||||
"b"
|
||||
"c"
|
||||
)
|
||||
|
||||
this_will_stay_on_three_lines = (
|
||||
"a" # comment
|
||||
"b"
|
||||
"c"
|
||||
)
|
||||
|
||||
this_will_also_become_one_line = ( # comment
|
||||
"a"
|
||||
"b"
|
||||
"c"
|
||||
)
|
||||
|
||||
assert some_var == expected_result, """
|
||||
test
|
||||
"""
|
||||
@@ -402,7 +421,18 @@ a = b if """
|
||||
[
|
||||
"""cow
|
||||
moos""",
|
||||
@@ -214,10 +253,8 @@
|
||||
@@ -206,7 +245,9 @@
|
||||
"c"
|
||||
)
|
||||
|
||||
-this_will_also_become_one_line = "abc" # comment
|
||||
+this_will_also_become_one_line = ( # comment
|
||||
+ "abc"
|
||||
+)
|
||||
|
||||
assert some_var == expected_result, """
|
||||
test
|
||||
@@ -224,10 +265,8 @@
|
||||
"""Sxxxxxxx xxxxxxxx, xxxxxxx xx xxxxxxxxx
|
||||
xxxxxxxxxxxxx xxxxxxx xxxxxxxxx xxx-xxxxxxxxxx xxxxxx xx xxx-xxxxxx"""
|
||||
),
|
||||
@@ -415,7 +445,7 @@ a = b if """
|
||||
},
|
||||
}
|
||||
|
||||
@@ -236,14 +273,12 @@
|
||||
@@ -246,14 +285,12 @@
|
||||
a
|
||||
a"""
|
||||
),
|
||||
@@ -676,6 +706,18 @@ Please use `--build-option` instead,
|
||||
`--global-option` is reserved to flags like `--verbose` or `--quiet`.
|
||||
"""
|
||||
|
||||
this_will_become_one_line = "abc"
|
||||
|
||||
this_will_stay_on_three_lines = (
|
||||
"a" # comment
|
||||
"b"
|
||||
"c"
|
||||
)
|
||||
|
||||
this_will_also_become_one_line = ( # comment
|
||||
"abc"
|
||||
)
|
||||
|
||||
assert some_var == expected_result, """
|
||||
test
|
||||
"""
|
||||
@@ -986,6 +1028,16 @@ Please use `--build-option` instead,
|
||||
`--global-option` is reserved to flags like `--verbose` or `--quiet`.
|
||||
"""
|
||||
|
||||
this_will_become_one_line = "abc"
|
||||
|
||||
this_will_stay_on_three_lines = (
|
||||
"a" # comment
|
||||
"b"
|
||||
"c"
|
||||
)
|
||||
|
||||
this_will_also_become_one_line = "abc" # comment
|
||||
|
||||
assert some_var == expected_result, """
|
||||
test
|
||||
"""
|
||||
|
||||
@@ -1,67 +0,0 @@
|
||||
---
|
||||
source: crates/ruff_python_formatter/tests/fixtures.rs
|
||||
---
|
||||
## Input
|
||||
|
||||
```python
|
||||
def foo(
|
||||
a, #type:int
|
||||
b, #type: str
|
||||
c, # type: List[int]
|
||||
d, # type: Dict[int, str]
|
||||
e, # type: ignore
|
||||
f, # type : ignore
|
||||
g, # type : ignore
|
||||
):
|
||||
pass
|
||||
```
|
||||
|
||||
## Black Differences
|
||||
|
||||
```diff
|
||||
--- Black
|
||||
+++ Ruff
|
||||
@@ -1,9 +1,9 @@
|
||||
def foo(
|
||||
- a, # type: int
|
||||
+ a, # type:int
|
||||
b, # type: str
|
||||
c, # type: List[int]
|
||||
- d, # type: Dict[int, str]
|
||||
- e, # type: ignore
|
||||
+ d, # type: Dict[int, str]
|
||||
+ e, # type: ignore
|
||||
f, # type : ignore
|
||||
g, # type : ignore
|
||||
):
|
||||
```
|
||||
|
||||
## Ruff Output
|
||||
|
||||
```python
|
||||
def foo(
|
||||
a, # type:int
|
||||
b, # type: str
|
||||
c, # type: List[int]
|
||||
d, # type: Dict[int, str]
|
||||
e, # type: ignore
|
||||
f, # type : ignore
|
||||
g, # type : ignore
|
||||
):
|
||||
pass
|
||||
```
|
||||
|
||||
## Black Output
|
||||
|
||||
```python
|
||||
def foo(
|
||||
a, # type: int
|
||||
b, # type: str
|
||||
c, # type: List[int]
|
||||
d, # type: Dict[int, str]
|
||||
e, # type: ignore
|
||||
f, # type : ignore
|
||||
g, # type : ignore
|
||||
):
|
||||
pass
|
||||
```
|
||||
@@ -1,85 +0,0 @@
|
||||
---
|
||||
source: crates/ruff_python_formatter/tests/fixtures.rs
|
||||
---
|
||||
## Input
|
||||
|
||||
```python
|
||||
# Remove unnecessary parentheses from LHS of assignments
|
||||
|
||||
|
||||
def a():
|
||||
return [1, 2, 3]
|
||||
|
||||
|
||||
# Single variable with unnecessary parentheses
|
||||
(b) = a()[0]
|
||||
|
||||
# Tuple unpacking with unnecessary parentheses
|
||||
(c, *_) = a()
|
||||
|
||||
# These should not be changed - parentheses are necessary
|
||||
(d,) = a() # single-element tuple
|
||||
e = (1 + 2) * 3 # RHS has precedence needs
|
||||
```
|
||||
|
||||
## Black Differences
|
||||
|
||||
```diff
|
||||
--- Black
|
||||
+++ Ruff
|
||||
@@ -6,10 +6,10 @@
|
||||
|
||||
|
||||
# Single variable with unnecessary parentheses
|
||||
-b = a()[0]
|
||||
+(b) = a()[0]
|
||||
|
||||
# Tuple unpacking with unnecessary parentheses
|
||||
-c, *_ = a()
|
||||
+(c, *_) = a()
|
||||
|
||||
# These should not be changed - parentheses are necessary
|
||||
(d,) = a() # single-element tuple
|
||||
```
|
||||
|
||||
## Ruff Output
|
||||
|
||||
```python
|
||||
# Remove unnecessary parentheses from LHS of assignments
|
||||
|
||||
|
||||
def a():
|
||||
return [1, 2, 3]
|
||||
|
||||
|
||||
# Single variable with unnecessary parentheses
|
||||
(b) = a()[0]
|
||||
|
||||
# Tuple unpacking with unnecessary parentheses
|
||||
(c, *_) = a()
|
||||
|
||||
# These should not be changed - parentheses are necessary
|
||||
(d,) = a() # single-element tuple
|
||||
e = (1 + 2) * 3 # RHS has precedence needs
|
||||
```
|
||||
|
||||
## Black Output
|
||||
|
||||
```python
|
||||
# Remove unnecessary parentheses from LHS of assignments
|
||||
|
||||
|
||||
def a():
|
||||
return [1, 2, 3]
|
||||
|
||||
|
||||
# Single variable with unnecessary parentheses
|
||||
b = a()[0]
|
||||
|
||||
# Tuple unpacking with unnecessary parentheses
|
||||
c, *_ = a()
|
||||
|
||||
# These should not be changed - parentheses are necessary
|
||||
(d,) = a() # single-element tuple
|
||||
e = (1 + 2) * 3 # RHS has precedence needs
|
||||
```
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "ruff_wasm"
|
||||
version = "0.14.11"
|
||||
version = "0.14.10"
|
||||
publish = false
|
||||
authors = { workspace = true }
|
||||
edition = { workspace = true }
|
||||
|
||||
@@ -7,6 +7,7 @@ use std::collections::BTreeMap;
|
||||
use std::env::VarError;
|
||||
use std::num::{NonZeroU8, NonZeroU16};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::str::FromStr;
|
||||
|
||||
use anyhow::{Context, Result, anyhow};
|
||||
use glob::{GlobError, Paths, PatternError, glob};
|
||||
@@ -35,7 +36,8 @@ use ruff_linter::settings::{
|
||||
DEFAULT_SELECTORS, DUMMY_VARIABLE_RGX, LinterSettings, TASK_TAGS, TargetVersion,
|
||||
};
|
||||
use ruff_linter::{
|
||||
RuleSelector, fs, warn_user_once, warn_user_once_by_id, warn_user_once_by_message,
|
||||
RUFF_PKG_VERSION, RuleSelector, fs, warn_user_once, warn_user_once_by_id,
|
||||
warn_user_once_by_message,
|
||||
};
|
||||
use ruff_python_ast as ast;
|
||||
use ruff_python_formatter::{
|
||||
@@ -51,7 +53,6 @@ use crate::options::{
|
||||
Flake8UnusedArgumentsOptions, FormatOptions, IsortOptions, LintCommonOptions, LintOptions,
|
||||
McCabeOptions, Options, Pep8NamingOptions, PyUpgradeOptions, PycodestyleOptions,
|
||||
PydoclintOptions, PydocstyleOptions, PyflakesOptions, PylintOptions, RuffOptions,
|
||||
validate_required_version,
|
||||
};
|
||||
use crate::settings::{
|
||||
EXCLUDE, FileResolverSettings, FormatterSettings, INCLUDE, INCLUDE_PREVIEW, LineEnding,
|
||||
@@ -154,7 +155,13 @@ pub struct Configuration {
|
||||
impl Configuration {
|
||||
pub fn into_settings(self, project_root: &Path) -> Result<Settings> {
|
||||
if let Some(required_version) = &self.required_version {
|
||||
validate_required_version(required_version)?;
|
||||
let ruff_pkg_version = pep440_rs::Version::from_str(RUFF_PKG_VERSION)
|
||||
.expect("RUFF_PKG_VERSION is not a valid PEP 440 version specifier");
|
||||
if !required_version.contains(&ruff_pkg_version) {
|
||||
return Err(anyhow!(
|
||||
"Required version `{required_version}` does not match the running version `{RUFF_PKG_VERSION}`"
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
let linter_target_version = TargetVersion(self.target_version);
|
||||
|
||||
@@ -1,19 +1,15 @@
|
||||
use anyhow::Result;
|
||||
use regex::Regex;
|
||||
use rustc_hash::{FxBuildHasher, FxHashMap, FxHashSet};
|
||||
use serde::de::{self};
|
||||
use serde::{Deserialize, Deserializer, Serialize};
|
||||
use std::collections::{BTreeMap, BTreeSet};
|
||||
use std::path::PathBuf;
|
||||
use std::str::FromStr;
|
||||
use strum::IntoEnumIterator;
|
||||
use unicode_normalization::UnicodeNormalization;
|
||||
|
||||
use crate::settings::LineEnding;
|
||||
use ruff_formatter::IndentStyle;
|
||||
use ruff_graph::Direction;
|
||||
use ruff_linter::RUFF_PKG_VERSION;
|
||||
|
||||
use ruff_linter::line_width::{IndentWidth, LineLength};
|
||||
use ruff_linter::rules::flake8_import_conventions::settings::BannedAliases;
|
||||
use ruff_linter::rules::flake8_pytest_style::settings::SettingsError;
|
||||
@@ -560,17 +556,6 @@ pub struct LintOptions {
|
||||
pub future_annotations: Option<bool>,
|
||||
}
|
||||
|
||||
pub fn validate_required_version(required_version: &RequiredVersion) -> anyhow::Result<()> {
|
||||
let ruff_pkg_version = pep440_rs::Version::from_str(RUFF_PKG_VERSION)
|
||||
.expect("RUFF_PKG_VERSION is not a valid PEP 440 version specifier");
|
||||
if !required_version.contains(&ruff_pkg_version) {
|
||||
return Err(anyhow::anyhow!(
|
||||
"Required version `{required_version}` does not match the running version `{RUFF_PKG_VERSION}`"
|
||||
));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Newtype wrapper for [`LintCommonOptions`] that allows customizing the JSON schema and omitting the fields from the [`OptionsMetadata`].
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Default, Serialize, Deserialize)]
|
||||
#[serde(transparent)]
|
||||
|
||||
@@ -5,13 +5,12 @@ use std::path::{Path, PathBuf};
|
||||
use anyhow::{Context, Result};
|
||||
use log::debug;
|
||||
use pep440_rs::{Operator, Version, VersionSpecifiers};
|
||||
use serde::de::DeserializeOwned;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use strum::IntoEnumIterator;
|
||||
|
||||
use ruff_linter::settings::types::{PythonVersion, RequiredVersion};
|
||||
use ruff_linter::settings::types::PythonVersion;
|
||||
|
||||
use crate::options::{Options, validate_required_version};
|
||||
use crate::options::Options;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
struct Tools {
|
||||
@@ -41,38 +40,20 @@ impl Pyproject {
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_toml<P: AsRef<Path>, T: DeserializeOwned>(path: P, table_path: &[&str]) -> Result<T> {
|
||||
/// Parse a `ruff.toml` file.
|
||||
fn parse_ruff_toml<P: AsRef<Path>>(path: P) -> Result<Options> {
|
||||
let path = path.as_ref();
|
||||
let contents = std::fs::read_to_string(path)
|
||||
.with_context(|| format!("Failed to read {}", path.display()))?;
|
||||
|
||||
// Parse the TOML document once into a spanned representation so we can:
|
||||
// - Inspect `required-version` without triggering strict deserialization errors.
|
||||
// - Deserialize with precise spans (line/column and excerpt) on errors.
|
||||
let root = toml::de::DeTable::parse(&contents)
|
||||
.with_context(|| format!("Failed to parse {}", path.display()))?;
|
||||
|
||||
check_required_version(root.get_ref(), table_path)?;
|
||||
|
||||
let deserializer = toml::de::Deserializer::from(root);
|
||||
T::deserialize(deserializer)
|
||||
.map_err(|mut err| {
|
||||
// `Deserializer::from` doesn't have access to the original input, but we do.
|
||||
// Attach it so TOML errors include line/column and a source excerpt.
|
||||
err.set_input(Some(&contents));
|
||||
err
|
||||
})
|
||||
.with_context(|| format!("Failed to parse {}", path.display()))
|
||||
}
|
||||
|
||||
/// Parse a `ruff.toml` file.
|
||||
fn parse_ruff_toml<P: AsRef<Path>>(path: P) -> Result<Options> {
|
||||
parse_toml(path, &[])
|
||||
toml::from_str(&contents).with_context(|| format!("Failed to parse {}", path.display()))
|
||||
}
|
||||
|
||||
/// Parse a `pyproject.toml` file.
|
||||
fn parse_pyproject_toml<P: AsRef<Path>>(path: P) -> Result<Pyproject> {
|
||||
parse_toml(path, &["tool", "ruff"])
|
||||
let path = path.as_ref();
|
||||
let contents = std::fs::read_to_string(path)
|
||||
.with_context(|| format!("Failed to read {}", path.display()))?;
|
||||
toml::from_str(&contents).with_context(|| format!("Failed to parse {}", path.display()))
|
||||
}
|
||||
|
||||
/// Return `true` if a `pyproject.toml` contains a `[tool.ruff]` section.
|
||||
@@ -117,33 +98,6 @@ pub fn find_settings_toml<P: AsRef<Path>>(path: P) -> Result<Option<PathBuf>> {
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
fn check_required_version(value: &toml::de::DeTable, table_path: &[&str]) -> Result<()> {
|
||||
let mut current = value;
|
||||
for key in table_path {
|
||||
let Some(next) = current.get(*key) else {
|
||||
return Ok(());
|
||||
};
|
||||
let toml::de::DeValue::Table(next) = next.get_ref() else {
|
||||
return Ok(());
|
||||
};
|
||||
current = next;
|
||||
}
|
||||
|
||||
let required_version = current
|
||||
.get("required-version")
|
||||
.and_then(|value| value.get_ref().as_str());
|
||||
|
||||
let Some(required_version) = required_version else {
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
// If it doesn't parse, we just fall through to normal parsing; it will give a nicer error message.
|
||||
if let Ok(required_version) = required_version.parse::<RequiredVersion>() {
|
||||
validate_required_version(&required_version)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Derive target version from `required-version` in `pyproject.toml`, if
|
||||
/// such a file exists in an ancestor directory.
|
||||
pub fn find_fallback_target_version<P: AsRef<Path>>(path: P) -> Option<PythonVersion> {
|
||||
|
||||
@@ -102,8 +102,8 @@ impl Relativity {
|
||||
#[derive(Debug)]
|
||||
pub struct Resolver<'a> {
|
||||
pyproject_config: &'a PyprojectConfig,
|
||||
/// All [`Settings`] that have been added to the resolver, along with their config file paths.
|
||||
settings: Vec<(Settings, PathBuf)>,
|
||||
/// All [`Settings`] that have been added to the resolver.
|
||||
settings: Vec<Settings>,
|
||||
/// A router from path to index into the `settings` vector.
|
||||
router: Router<usize>,
|
||||
}
|
||||
@@ -146,8 +146,8 @@ impl<'a> Resolver<'a> {
|
||||
}
|
||||
|
||||
/// Add a resolved [`Settings`] under a given [`PathBuf`] scope.
|
||||
fn add(&mut self, path: &Path, settings: Settings, config_path: PathBuf) {
|
||||
self.settings.push((settings, config_path));
|
||||
fn add(&mut self, path: &Path, settings: Settings) {
|
||||
self.settings.push(settings);
|
||||
|
||||
// Normalize the path to use `/` separators and escape the '{' and '}' characters,
|
||||
// which matchit uses for routing parameters.
|
||||
@@ -172,27 +172,13 @@ impl<'a> Resolver<'a> {
|
||||
|
||||
/// Return the appropriate [`Settings`] for a given [`Path`].
|
||||
pub fn resolve(&self, path: &Path) -> &Settings {
|
||||
self.resolve_with_path(path).0
|
||||
}
|
||||
|
||||
/// Return the appropriate [`Settings`] and config file path for a given [`Path`].
|
||||
pub fn resolve_with_path(&self, path: &Path) -> (&Settings, Option<&Path>) {
|
||||
match self.pyproject_config.strategy {
|
||||
PyprojectDiscoveryStrategy::Fixed => (
|
||||
&self.pyproject_config.settings,
|
||||
self.pyproject_config.path.as_deref(),
|
||||
),
|
||||
PyprojectDiscoveryStrategy::Fixed => &self.pyproject_config.settings,
|
||||
PyprojectDiscoveryStrategy::Hierarchical => self
|
||||
.router
|
||||
.at(path.to_slash_lossy().as_ref())
|
||||
.map(|Match { value, .. }| {
|
||||
let (settings, config_path) = &self.settings[*value];
|
||||
(settings, Some(config_path.as_path()))
|
||||
})
|
||||
.unwrap_or((
|
||||
&self.pyproject_config.settings,
|
||||
self.pyproject_config.path.as_deref(),
|
||||
)),
|
||||
.map(|Match { value, .. }| &self.settings[*value])
|
||||
.unwrap_or(&self.pyproject_config.settings),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -269,8 +255,7 @@ impl<'a> Resolver<'a> {
|
||||
|
||||
/// Return an iterator over the resolved [`Settings`] in this [`Resolver`].
|
||||
pub fn settings(&self) -> impl Iterator<Item = &Settings> {
|
||||
std::iter::once(&self.pyproject_config.settings)
|
||||
.chain(self.settings.iter().map(|(settings, _)| settings))
|
||||
std::iter::once(&self.pyproject_config.settings).chain(&self.settings)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -394,17 +379,17 @@ pub fn resolve_configuration(
|
||||
|
||||
/// Extract the project root (scope) and [`Settings`] from a given
|
||||
/// `pyproject.toml`.
|
||||
fn resolve_scoped_settings(
|
||||
pyproject: &Path,
|
||||
fn resolve_scoped_settings<'a>(
|
||||
pyproject: &'a Path,
|
||||
transformer: &dyn ConfigurationTransformer,
|
||||
origin: ConfigurationOrigin,
|
||||
) -> Result<(PathBuf, Settings)> {
|
||||
) -> Result<(&'a Path, Settings)> {
|
||||
let relativity = Relativity::from(origin);
|
||||
|
||||
let configuration = resolve_configuration(pyproject, transformer, origin)?;
|
||||
let project_root = relativity.resolve(pyproject);
|
||||
let settings = configuration.into_settings(project_root)?;
|
||||
Ok((project_root.to_path_buf(), settings))
|
||||
Ok((project_root, settings))
|
||||
}
|
||||
|
||||
/// Extract the [`Settings`] from a given `pyproject.toml` and process the
|
||||
@@ -470,7 +455,7 @@ pub fn python_files_in_path<'a>(
|
||||
transformer,
|
||||
ConfigurationOrigin::Ancestor,
|
||||
)?;
|
||||
resolver.add(&root, settings, pyproject);
|
||||
resolver.add(root, settings);
|
||||
// We found the closest configuration.
|
||||
break;
|
||||
}
|
||||
@@ -662,11 +647,7 @@ impl ParallelVisitor for PythonFilesVisitor<'_, '_> {
|
||||
ConfigurationOrigin::Ancestor,
|
||||
) {
|
||||
Ok((root, settings)) => {
|
||||
self.global
|
||||
.resolver
|
||||
.write()
|
||||
.unwrap()
|
||||
.add(&root, settings, pyproject);
|
||||
self.global.resolver.write().unwrap().add(root, settings);
|
||||
}
|
||||
Err(err) => {
|
||||
self.local_error = Err(err);
|
||||
@@ -786,7 +767,7 @@ pub fn python_file_at_path(
|
||||
if let Some(pyproject) = settings_toml(ancestor)? {
|
||||
let (root, settings) =
|
||||
resolve_scoped_settings(&pyproject, transformer, ConfigurationOrigin::Unknown)?;
|
||||
resolver.add(&root, settings, pyproject);
|
||||
resolver.add(root, settings);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
3
crates/ty/docs/cli.md
generated
3
crates/ty/docs/cli.md
generated
@@ -37,8 +37,7 @@ ty check [OPTIONS] [PATH]...
|
||||
|
||||
<h3 class="cli-reference">Options</h3>
|
||||
|
||||
<dl class="cli-reference"><dt id="ty-check--add-ignore"><a href="#ty-check--add-ignore"><code>--add-ignore</code></a></dt><dd><p>Adds <code>ty: ignore</code> comments to suppress all rule diagnostics</p>
|
||||
</dd><dt id="ty-check--color"><a href="#ty-check--color"><code>--color</code></a> <i>when</i></dt><dd><p>Control when colored output is used</p>
|
||||
<dl class="cli-reference"><dt id="ty-check--color"><a href="#ty-check--color"><code>--color</code></a> <i>when</i></dt><dd><p>Control when colored output is used</p>
|
||||
<p>Possible values:</p>
|
||||
<ul>
|
||||
<li><code>auto</code>: Display colors if the output goes to an interactive terminal</li>
|
||||
|
||||
244
crates/ty/docs/rules.md
generated
244
crates/ty/docs/rules.md
generated
@@ -8,7 +8,7 @@
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'warn'."><code>warn</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.20">0.0.1-alpha.20</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20ambiguous-protocol-member" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L540" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L538" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -80,7 +80,7 @@ def test(): -> "int":
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20call-non-callable" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L139" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L137" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -104,7 +104,7 @@ Calling a non-callable object will raise a `TypeError` at runtime.
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.7">0.0.7</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20call-top-callable" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L157" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L155" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -135,7 +135,7 @@ def f(x: object):
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20conflicting-argument-forms" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L208" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L206" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -167,7 +167,7 @@ f(int) # error
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20conflicting-declarations" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L234" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L232" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -198,7 +198,7 @@ a = 1
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20conflicting-metaclass" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L259" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L257" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -230,7 +230,7 @@ class C(A, B): ...
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20cyclic-class-definition" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L285" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L283" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -262,7 +262,7 @@ class B(A): ...
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Preview (since <a href="https://github.com/astral-sh/ty/releases/tag/1.0.0">1.0.0</a>) ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20cyclic-type-alias-definition" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L311" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L309" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -290,7 +290,7 @@ type B = A
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'warn'."><code>warn</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.16">0.0.1-alpha.16</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20deprecated" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L355" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L353" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -317,7 +317,7 @@ old_func() # emits [deprecated] diagnostic
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'ignore'."><code>ignore</code></a> ·
|
||||
Preview (since <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a>) ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20division-by-zero" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L333" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L331" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -346,7 +346,7 @@ false positives it can produce.
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20duplicate-base" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L376" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L374" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -373,7 +373,7 @@ class B(A, A): ...
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.12">0.0.1-alpha.12</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20duplicate-kw-only" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L397" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L395" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -467,7 +467,7 @@ def test(): -> "int":
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'warn'."><code>warn</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20ignore-comment-unknown-rule" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Fsuppression.rs#L54" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Fsuppression.rs#L50" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -529,7 +529,7 @@ def test(): -> "Literal[5]":
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20inconsistent-mro" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L623" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L621" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -559,7 +559,7 @@ class C(A, B): ...
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20index-out-of-bounds" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L647" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L645" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -585,7 +585,7 @@ t[3] # IndexError: tuple index out of range
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.12">0.0.1-alpha.12</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20instance-layout-conflict" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L429" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L427" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -674,7 +674,7 @@ an atypical memory layout.
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-argument-type" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L701" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L699" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -701,7 +701,7 @@ func("foo") # error: [invalid-argument-type]
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-assignment" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L741" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L739" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -729,7 +729,7 @@ a: int = ''
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-attribute-access" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L2044" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L2042" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -763,7 +763,7 @@ C.instance_var = 3 # error: Cannot assign to instance variable
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.19">0.0.1-alpha.19</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-await" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L763" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L761" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -799,7 +799,7 @@ asyncio.run(main())
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-base" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L793" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L791" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -823,7 +823,7 @@ class A(42): ... # error: [invalid-base]
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-context-manager" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L844" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L842" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -850,7 +850,7 @@ with 1:
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-declaration" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L865" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L863" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -879,7 +879,7 @@ a: str
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-exception-caught" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L888" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L886" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -923,7 +923,7 @@ except ZeroDivisionError:
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.28">0.0.1-alpha.28</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-explicit-override" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1714" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1712" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -965,7 +965,7 @@ class D(A):
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.35">0.0.1-alpha.35</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-frozen-dataclass-subclass" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L2295" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L2268" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -1009,7 +1009,7 @@ class NonFrozenChild(FrozenBase): # Error raised here
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-generic-class" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L924" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L922" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -1047,7 +1047,7 @@ class D(Generic[U, T]): ...
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'warn'."><code>warn</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-ignore-comment" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Fsuppression.rs#L79" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Fsuppression.rs#L75" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -1077,7 +1077,7 @@ a = 20 / 0 # type: ignore
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.17">0.0.1-alpha.17</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-key" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L668" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L666" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -1116,7 +1116,7 @@ carol = Person(name="Carol", age=25) # typo!
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-legacy-type-variable" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L955" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L953" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -1151,7 +1151,7 @@ def f(t: TypeVar("U")): ...
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-metaclass" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1052" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1050" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -1185,7 +1185,7 @@ class B(metaclass=f): ...
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.20">0.0.1-alpha.20</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-method-override" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L2197" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L2170" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -1292,7 +1292,7 @@ Correct use of `@override` is enforced by ty's `invalid-explicit-override` rule.
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.19">0.0.1-alpha.19</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-named-tuple" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L575" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L573" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -1346,7 +1346,7 @@ AttributeError: Cannot overwrite NamedTuple attribute _asdict
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Preview (since <a href="https://github.com/astral-sh/ty/releases/tag/1.0.0">1.0.0</a>) ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-newtype" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1028" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1026" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -1376,7 +1376,7 @@ Baz = NewType("Baz", int | str) # error: invalid base for `typing.NewType`
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-overload" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1079" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1077" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -1426,7 +1426,7 @@ def foo(x: int) -> int: ...
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-parameter-default" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1178" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1176" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -1452,7 +1452,7 @@ def f(a: int = ''): ...
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-paramspec" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L983" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L981" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -1483,7 +1483,7 @@ P2 = ParamSpec("S2") # error: ParamSpec name must match the variable it's assig
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-protocol" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L511" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L509" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -1517,7 +1517,7 @@ TypeError: Protocols can only inherit from other protocols, got <class 'int'>
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-raise" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1198" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1196" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -1566,7 +1566,7 @@ def g():
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-return-type" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L722" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L720" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -1591,7 +1591,7 @@ def func() -> int:
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-super-argument" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1241" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1239" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -1681,59 +1681,13 @@ class C: ...
|
||||
- [Typing spec: The meaning of annotations](https://typing.python.org/en/latest/spec/annotations.html#the-meaning-of-annotations)
|
||||
- [Typing spec: String annotations](https://typing.python.org/en/latest/spec/annotations.html#string-annotations)
|
||||
|
||||
## `invalid-total-ordering`
|
||||
|
||||
<small>
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.10">0.0.10</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-total-ordering" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L2333" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
**What it does**
|
||||
|
||||
Checks for classes decorated with `@functools.total_ordering` that don't
|
||||
define any ordering method (`__lt__`, `__le__`, `__gt__`, or `__ge__`).
|
||||
|
||||
**Why is this bad?**
|
||||
|
||||
The `@total_ordering` decorator requires the class to define at least one
|
||||
ordering method. If none is defined, Python raises a `ValueError` at runtime.
|
||||
|
||||
**Example**
|
||||
|
||||
|
||||
```python
|
||||
from functools import total_ordering
|
||||
|
||||
@total_ordering
|
||||
class MyClass: # Error: no ordering method defined
|
||||
def __eq__(self, other: object) -> bool:
|
||||
return True
|
||||
```
|
||||
|
||||
Use instead:
|
||||
|
||||
```python
|
||||
from functools import total_ordering
|
||||
|
||||
@total_ordering
|
||||
class MyClass:
|
||||
def __eq__(self, other: object) -> bool:
|
||||
return True
|
||||
|
||||
def __lt__(self, other: "MyClass") -> bool:
|
||||
return True
|
||||
```
|
||||
|
||||
## `invalid-type-alias-type`
|
||||
|
||||
<small>
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.6">0.0.1-alpha.6</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-type-alias-type" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1007" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1005" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -1760,7 +1714,7 @@ NewAlias = TypeAliasType(get_name(), int) # error: TypeAliasType name mus
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.29">0.0.1-alpha.29</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-type-arguments" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1473" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1471" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -1807,7 +1761,7 @@ Bar[int] # error: too few arguments
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-type-checking-constant" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1280" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1278" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -1837,7 +1791,7 @@ TYPE_CHECKING = ''
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-type-form" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1304" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1302" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -1867,7 +1821,7 @@ b: Annotated[int] # `Annotated` expects at least two arguments
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.11">0.0.1-alpha.11</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-type-guard-call" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1356" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1354" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -1901,7 +1855,7 @@ f(10) # Error
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.11">0.0.1-alpha.11</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-type-guard-definition" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1328" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1326" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -1935,7 +1889,7 @@ class C:
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-type-variable-constraints" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1384" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1382" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -1964,44 +1918,13 @@ T = TypeVar('T', bound=str) # valid bound TypeVar
|
||||
|
||||
[type variables]: https://docs.python.org/3/library/typing.html#typing.TypeVar
|
||||
|
||||
## `invalid-typed-dict-statement`
|
||||
|
||||
<small>
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.9">0.0.9</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-typed-dict-statement" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L2172" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
**What it does**
|
||||
|
||||
Detects statements other than annotated declarations in `TypedDict` class bodies.
|
||||
|
||||
**Why is this bad?**
|
||||
|
||||
`TypedDict` class bodies aren't allowed to contain any other types of statements. For
|
||||
example, method definitions and field values aren't allowed. None of these will be
|
||||
available on "instances of the `TypedDict`" at runtime (as `dict` is the runtime class of
|
||||
all "`TypedDict` instances").
|
||||
|
||||
**Example**
|
||||
|
||||
```python
|
||||
from typing import TypedDict
|
||||
|
||||
class Foo(TypedDict):
|
||||
def bar(self): # error: [invalid-typed-dict-statement]
|
||||
pass
|
||||
```
|
||||
|
||||
## `missing-argument`
|
||||
|
||||
<small>
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20missing-argument" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1413" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1411" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -2026,7 +1949,7 @@ func() # TypeError: func() missing 1 required positional argument: 'x'
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.20">0.0.1-alpha.20</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20missing-typed-dict-key" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L2145" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L2143" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -2059,7 +1982,7 @@ alice["age"] # KeyError
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20no-matching-overload" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1432" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1430" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -2088,7 +2011,7 @@ func("string") # error: [no-matching-overload]
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20not-iterable" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1514" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1512" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -2114,7 +2037,7 @@ for i in 34: # TypeError: 'int' object is not iterable
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20not-subscriptable" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1455" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1453" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -2138,7 +2061,7 @@ Subscripting an object that does not support it will raise a `TypeError` at runt
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.29">0.0.1-alpha.29</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20override-of-final-method" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1687" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1685" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -2171,7 +2094,7 @@ class B(A):
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20parameter-already-assigned" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1565" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1563" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -2198,7 +2121,7 @@ f(1, x=2) # Error raised here
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.22">0.0.1-alpha.22</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20positional-only-parameter-as-kwarg" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1898" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1896" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -2225,7 +2148,7 @@ f(x=1) # Error raised here
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'warn'."><code>warn</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.22">0.0.1-alpha.22</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20possibly-missing-attribute" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1586" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1584" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -2253,7 +2176,7 @@ A.c # AttributeError: type object 'A' has no attribute 'c'
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'warn'."><code>warn</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.22">0.0.1-alpha.22</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20possibly-missing-implicit-call" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L182" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L180" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -2285,7 +2208,7 @@ A()[0] # TypeError: 'A' object is not subscriptable
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'ignore'."><code>ignore</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.22">0.0.1-alpha.22</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20possibly-missing-import" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1608" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1606" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -2322,7 +2245,7 @@ from module import a # ImportError: cannot import name 'a' from 'module'
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'ignore'."><code>ignore</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20possibly-unresolved-reference" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1638" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1636" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -2386,7 +2309,7 @@ def test(): -> "int":
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'warn'."><code>warn</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20redundant-cast" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L2072" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L2070" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -2413,7 +2336,7 @@ cast(int, f()) # Redundant
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20static-assert-error" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L2020" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L2018" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -2443,7 +2366,7 @@ static_assert(int(2.0 * 3.0) == 6) # error: does not have a statically known tr
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20subclass-of-final-class" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1664" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1662" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -2472,7 +2395,7 @@ class B(A): ... # Error raised here
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Preview (since <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.30">0.0.1-alpha.30</a>) ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20super-call-in-named-tuple-method" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1832" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1830" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -2506,7 +2429,7 @@ class F(NamedTuple):
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20too-many-positional-arguments" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1772" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1770" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -2533,7 +2456,7 @@ f("foo") # Error raised here
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20type-assertion-failure" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1750" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1748" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -2561,7 +2484,7 @@ def _(x: int):
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unavailable-implicit-super-arguments" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1793" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1791" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -2607,7 +2530,7 @@ class A:
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'warn'."><code>warn</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20undefined-reveal" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1859" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1857" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -2631,7 +2554,7 @@ reveal_type(1) # NameError: name 'reveal_type' is not defined
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unknown-argument" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1877" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1875" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -2658,7 +2581,7 @@ f(x=1, y=2) # Error raised here
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unresolved-attribute" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1919" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1917" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -2686,7 +2609,7 @@ A().foo # AttributeError: 'A' object has no attribute 'foo'
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'warn'."><code>warn</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.15">0.0.1-alpha.15</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unresolved-global" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L2093" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L2091" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -2744,7 +2667,7 @@ def g():
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unresolved-import" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1941" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1939" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -2769,7 +2692,7 @@ import foo # ModuleNotFoundError: No module named 'foo'
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unresolved-reference" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1960" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1958" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -2794,7 +2717,7 @@ print(x) # NameError: name 'x' is not defined
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'warn'."><code>warn</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.7">0.0.1-alpha.7</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unsupported-base" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L811" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L809" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -2833,7 +2756,7 @@ class D(C): ... # error: [unsupported-base]
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unsupported-bool-conversion" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1534" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1532" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -2870,7 +2793,7 @@ b1 < b2 < b1 # exception raised here
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unsupported-operator" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1979" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1977" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -2895,7 +2818,7 @@ A() + A() # TypeError: unsupported operand type(s) for +: 'A' and 'A'
|
||||
## `unused-ignore-comment`
|
||||
|
||||
<small>
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'warn'."><code>warn</code></a> ·
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'ignore'."><code>ignore</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unused-ignore-comment" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Fsuppression.rs#L25" target="_blank">View source</a>
|
||||
@@ -2904,11 +2827,11 @@ Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.
|
||||
|
||||
**What it does**
|
||||
|
||||
Checks for `ty: ignore` or `type: ignore` directives that are no longer applicable.
|
||||
Checks for `type: ignore` or `ty: ignore` directives that are no longer applicable.
|
||||
|
||||
**Why is this bad?**
|
||||
|
||||
A `ty: ignore` directive that no longer matches any diagnostic violations is likely
|
||||
A `type: ignore` directive that no longer matches any diagnostic violations is likely
|
||||
included by mistake, and should be removed to avoid confusion.
|
||||
|
||||
**Examples**
|
||||
@@ -2923,18 +2846,13 @@ Use instead:
|
||||
a = 20 / 2
|
||||
```
|
||||
|
||||
**Options**
|
||||
|
||||
Set [`analysis.respect-type-ignore-comments`](https://docs.astral.sh/ty/reference/configuration/#respect-type-ignore-comments)
|
||||
to `false` to prevent this rule from reporting unused `type: ignore` comments.
|
||||
|
||||
## `useless-overload-body`
|
||||
|
||||
<small>
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'warn'."><code>warn</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.22">0.0.1-alpha.22</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20useless-overload-body" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1122" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1120" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -2997,7 +2915,7 @@ def foo(x: int | str) -> int | str:
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20zero-stepsize-in-slice" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L2001" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1999" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user