Compare commits
181 Commits
fix-set-ch
...
4404_fix_e
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2abdc2540a | ||
|
|
1e36145972 | ||
|
|
8e06140d1d | ||
|
|
015895bcae | ||
|
|
36e01ad6eb | ||
|
|
ddfdc3bb01 | ||
|
|
bd2c50be86 | ||
|
|
48f4f2d63d | ||
|
|
94abf7f088 | ||
|
|
e3c12764f8 | ||
|
|
b8d378b0a3 | ||
|
|
0e028142f4 | ||
|
|
361d45f2b2 | ||
|
|
be11cae619 | ||
|
|
2b82caa163 | ||
|
|
51bc758d18 | ||
|
|
a6cf31cc89 | ||
|
|
524a2045ba | ||
|
|
a0b750f74b | ||
|
|
195b36c429 | ||
|
|
5c416e4d9b | ||
|
|
763d38cafb | ||
|
|
653a0ebf2d | ||
|
|
95448ba669 | ||
|
|
f18e10183f | ||
|
|
98920909c6 | ||
|
|
e1e1d2d341 | ||
|
|
4b9b6829dc | ||
|
|
be107dad64 | ||
|
|
d0ad1ed0af | ||
|
|
b3240dbfa2 | ||
|
|
fd1dfc3bfa | ||
|
|
b9754bd5c5 | ||
|
|
307f7a735c | ||
|
|
3af9dfeb0a | ||
|
|
5526699535 | ||
|
|
fab2a4adf7 | ||
|
|
13813dc1b1 | ||
|
|
70c01257ca | ||
|
|
26d19655db | ||
|
|
1f856aa576 | ||
|
|
1e383483f7 | ||
|
|
89b328c6be | ||
|
|
6143065fc2 | ||
|
|
107a295af4 | ||
|
|
c811213302 | ||
|
|
5ea3e42513 | ||
|
|
66089e1a2e | ||
|
|
097823b56d | ||
|
|
ed8113267c | ||
|
|
c654280d84 | ||
|
|
99486b38f4 | ||
|
|
716cab2f19 | ||
|
|
9ab16fb417 | ||
|
|
458beccf14 | ||
|
|
ccbc863960 | ||
|
|
71b3130ff1 | ||
|
|
08cd140ea6 | ||
|
|
848f184b8c | ||
|
|
56476dfd61 | ||
|
|
bae183b823 | ||
|
|
65dbfd2556 | ||
|
|
86ff1febea | ||
|
|
a33bbe6335 | ||
|
|
c992cfa76e | ||
|
|
916f0889f8 | ||
|
|
c1fd2c8a8e | ||
|
|
732b0405d7 | ||
|
|
e7316c1cc6 | ||
|
|
6f10aeebaa | ||
|
|
c74ef77e85 | ||
|
|
1e497162d1 | ||
|
|
aa41ffcfde | ||
|
|
bf5fbf8971 | ||
|
|
fc6580592d | ||
|
|
4d9b0b925d | ||
|
|
0daeea1f42 | ||
|
|
3f6584b74f | ||
|
|
c2fa568b46 | ||
|
|
1895011ac2 | ||
|
|
364bd82aee | ||
|
|
f9f08d6b03 | ||
|
|
b0984a2868 | ||
|
|
a431dd0368 | ||
|
|
099a9152d1 | ||
|
|
19f972a305 | ||
|
|
b0f89fa814 | ||
|
|
65312bad01 | ||
|
|
7b4dde0c6c | ||
|
|
e1fd3965a2 | ||
|
|
95ee6dcb3b | ||
|
|
cc44349401 | ||
|
|
a477720f4e | ||
|
|
be2fa6d217 | ||
|
|
cbd4c10fdd | ||
|
|
e2130707f5 | ||
|
|
780336db0a | ||
|
|
7e37d8916c | ||
|
|
ab11dd08df | ||
|
|
4080f36850 | ||
|
|
6d861743c8 | ||
|
|
54e103fc99 | ||
|
|
3470dee7d4 | ||
|
|
cb4f086cbf | ||
|
|
a77d2df934 | ||
|
|
638c18f007 | ||
|
|
70e6c212d9 | ||
|
|
9db622afe1 | ||
|
|
d3aa81a474 | ||
|
|
d8f5d2d767 | ||
|
|
e586c27590 | ||
|
|
8161757229 | ||
|
|
6a5f317362 | ||
|
|
c3d1fa851e | ||
|
|
eac3a0cc3d | ||
|
|
31067e6ce2 | ||
|
|
68b6d30c46 | ||
|
|
ab3c02342b | ||
|
|
9f7cc86a22 | ||
|
|
445e1723ab | ||
|
|
42c8054268 | ||
|
|
2d597bc1fb | ||
|
|
7275c16d98 | ||
|
|
02b8ce82af | ||
|
|
5abb8ec0dc | ||
|
|
f401050878 | ||
|
|
c1ac50093c | ||
|
|
1d756dc3a7 | ||
|
|
e86f12a1ec | ||
|
|
5c502a3320 | ||
|
|
901bcb6f21 | ||
|
|
111e1f93ca | ||
|
|
68d52da43b | ||
|
|
646ab64850 | ||
|
|
1accbeffd6 | ||
|
|
548a3cbb3f | ||
|
|
16d1e63a5e | ||
|
|
d647105e97 | ||
|
|
63fdcea29e | ||
|
|
2bb32ee943 | ||
|
|
ee1f094834 | ||
|
|
efd8f3bdab | ||
|
|
293889a352 | ||
|
|
2c19000e4a | ||
|
|
aba073a791 | ||
|
|
d042eddccc | ||
|
|
775d247731 | ||
|
|
58d08219e8 | ||
|
|
902c4e7d77 | ||
|
|
68969240c5 | ||
|
|
07cc4bcb0f | ||
|
|
9c3fb23ace | ||
|
|
467df23e65 | ||
|
|
c8442e91ce | ||
|
|
6bef347a8e | ||
|
|
c1cc6f3be1 | ||
|
|
83cf6d6e2f | ||
|
|
23abad0bd5 | ||
|
|
651d89794c | ||
|
|
39a1f3980f | ||
|
|
4b78141f6b | ||
|
|
5235977abc | ||
|
|
01d3d4bbd2 | ||
|
|
ac4a4da50e | ||
|
|
a6d269f263 | ||
|
|
f17282d615 | ||
|
|
6950c93934 | ||
|
|
ae75b303f0 | ||
|
|
20240fc3d9 | ||
|
|
f990d9dcc5 | ||
|
|
5c48414093 | ||
|
|
bcf745c5ba | ||
|
|
2f125f4019 | ||
|
|
6ab3fc60f4 | ||
|
|
222ca98a41 | ||
|
|
ec609f5c3b | ||
|
|
b9060ea2bd | ||
|
|
b56a799417 | ||
|
|
780d153ae8 | ||
|
|
7cc205b5d6 | ||
|
|
e1df2b1400 |
9
.github/CODEOWNERS
vendored
Normal file
9
.github/CODEOWNERS
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
# GitHub code owners file. For more info: https://help.github.com/articles/about-codeowners/
|
||||
#
|
||||
# - Comment lines begin with `#` character.
|
||||
# - Each line is a file pattern followed by one or more owners.
|
||||
# - The '*' pattern is global owners.
|
||||
# - Order is important. The last matching pattern has the most precedence.
|
||||
|
||||
# Jupyter
|
||||
/crates/ruff/src/jupyter/ @dhruvmanila
|
||||
19
.github/workflows/benchmark.yaml
vendored
19
.github/workflows/benchmark.yaml
vendored
@@ -14,7 +14,7 @@ jobs:
|
||||
name: "Run | ${{ matrix.os }}"
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, windows-latest]
|
||||
os: [ ubuntu-latest, windows-latest ]
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
steps:
|
||||
@@ -29,10 +29,7 @@ jobs:
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
|
||||
- name: "PR - Build benchmarks"
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: bench
|
||||
args: -p ruff_benchmark --no-run
|
||||
run: cargo bench -p ruff_benchmark --no-run
|
||||
|
||||
- name: "PR - Run benchmarks"
|
||||
run: cargo benchmark --save-baseline=pr
|
||||
@@ -47,10 +44,7 @@ jobs:
|
||||
run: rustup show
|
||||
|
||||
- name: "Main - Build benchmarks"
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: bench
|
||||
args: -p ruff_benchmark --no-run
|
||||
run: cargo bench -p ruff_benchmark --no-run
|
||||
|
||||
- name: "Main - Run benchmarks"
|
||||
run: cargo benchmark --save-baseline=main
|
||||
@@ -78,11 +72,10 @@ jobs:
|
||||
- name: "Install Rust toolchain"
|
||||
run: rustup show
|
||||
|
||||
- name: "Install cargo-binstall"
|
||||
uses: taiki-e/install-action@cargo-binstall
|
||||
|
||||
- name: "Install critcmp"
|
||||
run: cargo binstall critcmp -y
|
||||
uses: taiki-e/install-action@v2
|
||||
with:
|
||||
tool: critcmp
|
||||
|
||||
- name: "Linux | Download PR benchmark results"
|
||||
uses: actions/download-artifact@v3
|
||||
|
||||
31
.github/workflows/ci.yaml
vendored
31
.github/workflows/ci.yaml
vendored
@@ -2,7 +2,7 @@ name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
branches: [ main ]
|
||||
pull_request:
|
||||
workflow_dispatch:
|
||||
|
||||
@@ -54,7 +54,7 @@ jobs:
|
||||
cargo-test:
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, windows-latest]
|
||||
os: [ ubuntu-latest, windows-latest ]
|
||||
runs-on: ${{ matrix.os }}
|
||||
name: "cargo test | ${{ matrix.os }}"
|
||||
steps:
|
||||
@@ -87,6 +87,22 @@ jobs:
|
||||
name: ruff
|
||||
path: target/debug/ruff
|
||||
|
||||
cargo-fuzz:
|
||||
runs-on: ubuntu-latest
|
||||
name: "cargo fuzz"
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: "Install Rust toolchain"
|
||||
run: rustup show
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
workspaces: "fuzz -> target"
|
||||
- name: "Install cargo-fuzz"
|
||||
uses: taiki-e/install-action@v2
|
||||
with:
|
||||
tool: cargo-fuzz@0.11
|
||||
- run: cargo fuzz build -s none
|
||||
|
||||
cargo-test-wasm:
|
||||
runs-on: ubuntu-latest
|
||||
name: "cargo test (wasm)"
|
||||
@@ -178,12 +194,12 @@ jobs:
|
||||
- uses: actions/checkout@v3
|
||||
- name: "Install nightly Rust toolchain"
|
||||
# Only pinned to make caching work, update freely
|
||||
run: rustup toolchain install nightly-2023-03-30
|
||||
run: rustup toolchain install nightly-2023-06-08
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
- name: "Install cargo-udeps"
|
||||
uses: taiki-e/install-action@cargo-udeps
|
||||
- name: "Run cargo-udeps"
|
||||
run: cargo +nightly-2023-03-30 udeps
|
||||
run: cargo +nightly-2023-06-08 udeps
|
||||
|
||||
|
||||
python-package:
|
||||
@@ -195,6 +211,7 @@ jobs:
|
||||
with:
|
||||
python-version: ${{ env.PYTHON_VERSION }}
|
||||
architecture: x64
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
- name: "Prep README.md"
|
||||
run: python scripts/transform_readme.py --target pypi
|
||||
- name: "Build wheels"
|
||||
@@ -207,6 +224,8 @@ jobs:
|
||||
pip install dist/${{ env.PACKAGE_NAME }}-*.whl --force-reinstall
|
||||
ruff --help
|
||||
python -m ruff --help
|
||||
- name: "Remove wheels from cache"
|
||||
run: rm -rf target/wheels
|
||||
|
||||
pre-commit:
|
||||
name: "pre-commit"
|
||||
@@ -224,8 +243,8 @@ jobs:
|
||||
- name: "Cache pre-commit"
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ~/.cache/pre-commit
|
||||
key: pre-commit-${{ hashFiles('.pre-commit-config.yaml') }}
|
||||
path: ~/.cache/pre-commit
|
||||
key: pre-commit-${{ hashFiles('.pre-commit-config.yaml') }}
|
||||
- name: "Run pre-commit"
|
||||
run: |
|
||||
echo '```console' > $GITHUB_STEP_SUMMARY
|
||||
|
||||
6
.github/workflows/flake8-to-ruff.yaml
vendored
6
.github/workflows/flake8-to-ruff.yaml
vendored
@@ -66,7 +66,7 @@ jobs:
|
||||
runs-on: windows-latest
|
||||
strategy:
|
||||
matrix:
|
||||
target: [x64, x86]
|
||||
target: [ x64, x86 ]
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-python@v4
|
||||
@@ -94,7 +94,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
target: [x86_64, i686]
|
||||
target: [ x86_64, i686 ]
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-python@v4
|
||||
@@ -121,7 +121,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
target: [aarch64, armv7, s390x, ppc64le, ppc64]
|
||||
target: [ aarch64, armv7, s390x, ppc64le, ppc64 ]
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-python@v4
|
||||
|
||||
4
.github/workflows/pr-comment.yaml
vendored
4
.github/workflows/pr-comment.yaml
vendored
@@ -2,8 +2,8 @@ name: PR Check Comment
|
||||
|
||||
on:
|
||||
workflow_run:
|
||||
workflows: [CI, Benchmark]
|
||||
types: [completed]
|
||||
workflows: [ CI, Benchmark ]
|
||||
types: [ completed ]
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
workflow_run_id:
|
||||
|
||||
7
.github/workflows/release.yaml
vendored
7
.github/workflows/release.yaml
vendored
@@ -34,6 +34,7 @@ jobs:
|
||||
args: --out dist
|
||||
- name: "Test sdist"
|
||||
run: |
|
||||
rustup default $(cat rust-toolchain)
|
||||
pip install dist/${{ env.PACKAGE_NAME }}-*.tar.gz --force-reinstall
|
||||
ruff --help
|
||||
python -m ruff --help
|
||||
@@ -220,7 +221,7 @@ jobs:
|
||||
platform:
|
||||
- target: aarch64-unknown-linux-gnu
|
||||
arch: aarch64
|
||||
# see https://github.com/charliermarsh/ruff/issues/3791
|
||||
# see https://github.com/astral-sh/ruff/issues/3791
|
||||
# and https://github.com/gnzlbg/jemallocator/issues/170#issuecomment-1503228963
|
||||
maturin_docker_options: -e JEMALLOC_SYS_WITH_LG_PAGE=16
|
||||
- target: armv7-unknown-linux-gnueabihf
|
||||
@@ -399,6 +400,8 @@ jobs:
|
||||
permissions:
|
||||
# For pypi trusted publishing
|
||||
id-token: write
|
||||
# For GitHub release publishing
|
||||
contents: write
|
||||
steps:
|
||||
- uses: actions/download-artifact@v3
|
||||
with:
|
||||
@@ -414,7 +417,7 @@ jobs:
|
||||
with:
|
||||
name: binaries
|
||||
path: binaries
|
||||
- name: Release
|
||||
- name: "Publish to GitHub"
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
files: binaries/*
|
||||
|
||||
5
.gitignore
vendored
5
.gitignore
vendored
@@ -6,6 +6,11 @@ github_search*.jsonl
|
||||
schemastore
|
||||
.venv*
|
||||
scratch.py
|
||||
perf.data
|
||||
perf.data.old
|
||||
flamegraph.svg
|
||||
# Additional target directories that don't invalidate the main compile cache when changing linker settings
|
||||
/target*
|
||||
|
||||
###
|
||||
# Rust.gitignore
|
||||
|
||||
@@ -3,6 +3,7 @@ fail_fast: true
|
||||
exclude: |
|
||||
(?x)^(
|
||||
crates/ruff/resources/.*|
|
||||
crates/ruff/src/rules/.*/snapshots/.*|
|
||||
crates/ruff_python_formatter/resources/.*|
|
||||
crates/ruff_python_formatter/src/snapshots/.*
|
||||
)$
|
||||
@@ -37,29 +38,19 @@ repos:
|
||||
name: cargo fmt
|
||||
entry: cargo fmt --
|
||||
language: system
|
||||
types: [rust]
|
||||
- id: clippy
|
||||
name: clippy
|
||||
entry: cargo clippy --workspace --all-targets --all-features -- -D warnings
|
||||
language: system
|
||||
pass_filenames: false
|
||||
types: [ rust ]
|
||||
pass_filenames: false # This makes it a lot faster
|
||||
- id: ruff
|
||||
name: ruff
|
||||
entry: cargo run -p ruff_cli -- check --no-cache --force-exclude --fix --exit-non-zero-on-fix
|
||||
entry: cargo run --bin ruff -- check --no-cache --force-exclude --fix --exit-non-zero-on-fix
|
||||
language: system
|
||||
types_or: [python, pyi]
|
||||
types_or: [ python, pyi ]
|
||||
require_serial: true
|
||||
exclude: |
|
||||
(?x)^(
|
||||
crates/ruff/resources/.*|
|
||||
crates/ruff_python_formatter/resources/.*
|
||||
)$
|
||||
- id: dev-generate-all
|
||||
name: dev-generate-all
|
||||
entry: cargo dev generate-all
|
||||
language: system
|
||||
pass_filenames: false
|
||||
exclude: target
|
||||
|
||||
# Black
|
||||
- repo: https://github.com/psf/black
|
||||
@@ -68,4 +59,4 @@ repos:
|
||||
- id: black
|
||||
|
||||
ci:
|
||||
skip: [cargo-fmt, clippy, dev-generate-all]
|
||||
skip: [ cargo-fmt, dev-generate-all ]
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
## 0.0.268
|
||||
|
||||
### The `keep-runtime-typing` setting has been removed ([#4427](https://github.com/charliermarsh/ruff/pull/4427))
|
||||
### The `keep-runtime-typing` setting has been removed ([#4427](https://github.com/astral-sh/ruff/pull/4427))
|
||||
|
||||
Enabling the `keep-runtime-typing` option, located under the `pyupgrade` section, is equivalent
|
||||
to ignoring the `UP006` and `UP007` rules via Ruff's standard `ignore` mechanism. As there's no
|
||||
@@ -11,9 +11,9 @@ removed.
|
||||
|
||||
## 0.0.267
|
||||
|
||||
### `update-check` is no longer a valid configuration option ([#4313](https://github.com/charliermarsh/ruff/pull/4313))
|
||||
### `update-check` is no longer a valid configuration option ([#4313](https://github.com/astral-sh/ruff/pull/4313))
|
||||
|
||||
The `update-check` functionality was deprecated in [#2530](https://github.com/charliermarsh/ruff/pull/2530),
|
||||
The `update-check` functionality was deprecated in [#2530](https://github.com/astral-sh/ruff/pull/2530),
|
||||
in that the behavior itself was removed, and Ruff was changed to warn when that option was enabled.
|
||||
|
||||
Now, Ruff will throw an error when `update-check` is provided via a configuration file (e.g.,
|
||||
@@ -22,7 +22,7 @@ this option from their configuration.
|
||||
|
||||
## 0.0.265
|
||||
|
||||
### `--fix-only` now exits with a zero exit code, unless `--exit-non-zero-on-fix` is specified ([#4146](https://github.com/charliermarsh/ruff/pull/4146))
|
||||
### `--fix-only` now exits with a zero exit code, unless `--exit-non-zero-on-fix` is specified ([#4146](https://github.com/astral-sh/ruff/pull/4146))
|
||||
|
||||
Previously, `--fix-only` would exit with a non-zero exit code if any fixes were applied. This
|
||||
behavior was inconsistent with `--fix`, and further, meant that `--exit-non-zero-on-fix` was
|
||||
@@ -33,7 +33,7 @@ in which case it will exit with a non-zero exit code if any fixes were applied.
|
||||
|
||||
## 0.0.260
|
||||
|
||||
### Fixes are now represented as a list of edits ([#3709](https://github.com/charliermarsh/ruff/pull/3709))
|
||||
### Fixes are now represented as a list of edits ([#3709](https://github.com/astral-sh/ruff/pull/3709))
|
||||
|
||||
Previously, Ruff represented each fix as a single edit, which prohibited Ruff from automatically
|
||||
fixing violations that required multiple edits across a file. As such, Ruff now represents each
|
||||
@@ -68,14 +68,14 @@ The updated representation instead includes a list of edits:
|
||||
|
||||
## 0.0.246
|
||||
|
||||
### `multiple-statements-on-one-line-def` (`E704`) was removed ([#2773](https://github.com/charliermarsh/ruff/pull/2773))
|
||||
### `multiple-statements-on-one-line-def` (`E704`) was removed ([#2773](https://github.com/astral-sh/ruff/pull/2773))
|
||||
|
||||
This rule was introduced in v0.0.245. However, it turns out that pycodestyle and Flake8 ignore this
|
||||
rule by default, as it is not part of PEP 8. As such, we've removed it from Ruff.
|
||||
|
||||
## 0.0.245
|
||||
|
||||
### Ruff's public `check` method was removed ([#2709](https://github.com/charliermarsh/ruff/pull/2709))
|
||||
### Ruff's public `check` method was removed ([#2709](https://github.com/astral-sh/ruff/pull/2709))
|
||||
|
||||
Previously, Ruff exposed a `check` method as a public Rust API. This method was used by few,
|
||||
if any clients, and was not well documented or supported. As such, it has been removed, with
|
||||
@@ -83,11 +83,11 @@ the intention of adding a stable public API in the future.
|
||||
|
||||
## 0.0.238
|
||||
|
||||
### `select`, `extend-select`, `ignore`, and `extend-ignore` have new semantics ([#2312](https://github.com/charliermarsh/ruff/pull/2312))
|
||||
### `select`, `extend-select`, `ignore`, and `extend-ignore` have new semantics ([#2312](https://github.com/astral-sh/ruff/pull/2312))
|
||||
|
||||
Previously, the interplay between `select` and its related options could lead to unexpected
|
||||
behavior. For example, `ruff --select E501 --ignore ALL` and `ruff --select E501 --extend-ignore ALL`
|
||||
behaved differently. (See [#2312](https://github.com/charliermarsh/ruff/pull/2312) for more
|
||||
behaved differently. (See [#2312](https://github.com/astral-sh/ruff/pull/2312) for more
|
||||
examples.)
|
||||
|
||||
When Ruff determines the enabled rule set, it has to reconcile `select` and `ignore` from a variety
|
||||
@@ -113,14 +113,14 @@ ignore = ["F401"]
|
||||
Running `ruff --select F` would previously have enabled all `F` rules, apart from `F401`. Now, it
|
||||
will enable all `F` rules, including `F401`, as the command line's `--select` resets the resolution.
|
||||
|
||||
### `remove-six-compat` (`UP016`) has been removed ([#2332](https://github.com/charliermarsh/ruff/pull/2332))
|
||||
### `remove-six-compat` (`UP016`) has been removed ([#2332](https://github.com/astral-sh/ruff/pull/2332))
|
||||
|
||||
The `remove-six-compat` rule has been removed. This rule was only useful for one-time Python 2-to-3
|
||||
upgrades.
|
||||
|
||||
## 0.0.237
|
||||
|
||||
### `--explain`, `--clean`, and `--generate-shell-completion` are now subcommands ([#2190](https://github.com/charliermarsh/ruff/pull/2190))
|
||||
### `--explain`, `--clean`, and `--generate-shell-completion` are now subcommands ([#2190](https://github.com/astral-sh/ruff/pull/2190))
|
||||
|
||||
`--explain`, `--clean`, and `--generate-shell-completion` are now implemented as subcommands:
|
||||
|
||||
@@ -163,14 +163,14 @@ no change in behavior. However, please note the following exceptions:
|
||||
|
||||
## 0.0.226
|
||||
|
||||
### `misplaced-comparison-constant` (`PLC2201`) was deprecated in favor of `SIM300` ([#1980](https://github.com/charliermarsh/ruff/pull/1980))
|
||||
### `misplaced-comparison-constant` (`PLC2201`) was deprecated in favor of `SIM300` ([#1980](https://github.com/astral-sh/ruff/pull/1980))
|
||||
|
||||
These two rules contain (nearly) identical logic. To deduplicate the rule set, we've upgraded
|
||||
`SIM300` to handle a few more cases, and deprecated `PLC2201` in favor of `SIM300`.
|
||||
|
||||
## 0.0.225
|
||||
|
||||
### `@functools.cache` rewrites have been moved to a standalone rule (`UP033`) ([#1938](https://github.com/charliermarsh/ruff/pull/1938))
|
||||
### `@functools.cache` rewrites have been moved to a standalone rule (`UP033`) ([#1938](https://github.com/astral-sh/ruff/pull/1938))
|
||||
|
||||
Previously, `UP011` handled both `@functools.lru_cache()`-to-`@functools.lru_cache` conversions,
|
||||
_and_ `@functools.lru_cache(maxsize=None)`-to-`@functools.cache` conversions. The latter has been
|
||||
@@ -179,7 +179,7 @@ to reflect the change in rule code.
|
||||
|
||||
## 0.0.222
|
||||
|
||||
### `--max-complexity` has been removed from the CLI ([#1877](https://github.com/charliermarsh/ruff/pull/1877))
|
||||
### `--max-complexity` has been removed from the CLI ([#1877](https://github.com/astral-sh/ruff/pull/1877))
|
||||
|
||||
The McCabe plugin's `--max-complexity` setting has been removed from the CLI, for consistency with
|
||||
the treatment of other, similar settings.
|
||||
@@ -194,7 +194,7 @@ max-complexity = 10
|
||||
|
||||
## 0.0.181
|
||||
|
||||
### Files excluded by `.gitignore` are now ignored ([#1234](https://github.com/charliermarsh/ruff/pull/1234))
|
||||
### Files excluded by `.gitignore` are now ignored ([#1234](https://github.com/astral-sh/ruff/pull/1234))
|
||||
|
||||
Ruff will now avoid checking files that are excluded by `.ignore`, `.gitignore`,
|
||||
`.git/info/exclude`, and global `gitignore` files. This behavior is powered by the [`ignore`](https://docs.rs/ignore/latest/ignore/struct.WalkBuilder.html#ignore-rules)
|
||||
@@ -207,7 +207,7 @@ default.
|
||||
|
||||
## 0.0.178
|
||||
|
||||
### Configuration files are now resolved hierarchically ([#1190](https://github.com/charliermarsh/ruff/pull/1190))
|
||||
### Configuration files are now resolved hierarchically ([#1190](https://github.com/astral-sh/ruff/pull/1190))
|
||||
|
||||
`pyproject.toml` files are now resolved hierarchically, such that for each Python file, we find
|
||||
the first `pyproject.toml` file in its path, and use that to determine its lint settings.
|
||||
|
||||
104
CONTRIBUTING.md
104
CONTRIBUTING.md
@@ -21,18 +21,18 @@ Ruff welcomes contributions in the form of Pull Requests.
|
||||
For small changes (e.g., bug fixes), feel free to submit a PR.
|
||||
|
||||
For larger changes (e.g., new lint rules, new functionality, new configuration options), consider
|
||||
creating an [**issue**](https://github.com/charliermarsh/ruff/issues) outlining your proposed
|
||||
change. You can also join us on [**Discord**](https://discord.gg/c9MhzV8aU5) to discuss your idea with
|
||||
the community.
|
||||
creating an [**issue**](https://github.com/astral-sh/ruff/issues) outlining your proposed change.
|
||||
You can also join us on [**Discord**](https://discord.gg/c9MhzV8aU5) to discuss your idea with the
|
||||
community.
|
||||
|
||||
If you're looking for a place to start, we recommend implementing a new lint rule (see:
|
||||
[_Adding a new lint rule_](#example-adding-a-new-lint-rule), which will allow you to learn from and
|
||||
pattern-match against the examples in the existing codebase. Many lint rules are inspired by
|
||||
existing Python plugins, which can be used as a reference implementation.
|
||||
|
||||
As a concrete example: consider taking on one of the rules from the [`flake8-pyi`](https://github.com/charliermarsh/ruff/issues/848)
|
||||
plugin, and looking to the originating [Python source](https://github.com/PyCQA/flake8-pyi)
|
||||
for guidance.
|
||||
As a concrete example: consider taking on one of the rules from the [`flake8-pyi`](https://github.com/astral-sh/ruff/issues/848)
|
||||
plugin, and looking to the originating [Python source](https://github.com/PyCQA/flake8-pyi) for
|
||||
guidance.
|
||||
|
||||
### Prerequisites
|
||||
|
||||
@@ -45,6 +45,12 @@ You'll also need [Insta](https://insta.rs/docs/) to update snapshot tests:
|
||||
cargo install cargo-insta
|
||||
```
|
||||
|
||||
and pre-commit to run some validation checks:
|
||||
|
||||
```shell
|
||||
pipx install pre-commit # or `pip install pre-commit` if you have a virtualenv
|
||||
```
|
||||
|
||||
### Development
|
||||
|
||||
After cloning the repository, run Ruff locally with:
|
||||
@@ -57,9 +63,9 @@ Prior to opening a pull request, ensure that your code has been auto-formatted,
|
||||
and that it passes both the lint and test validation checks:
|
||||
|
||||
```shell
|
||||
cargo fmt # Auto-formatting...
|
||||
cargo clippy --fix --workspace --all-targets --all-features # Linting...
|
||||
cargo test # Testing...
|
||||
cargo clippy --workspace --all-targets --all-features -- -D warnings # Rust linting
|
||||
RUFF_UPDATE_SCHEMA=1 cargo test # Rust testing and updating ruff.schema.json
|
||||
pre-commit run --all-files --show-diff-on-failure # Rust and Python formatting, Markdown and Python linting, etc.
|
||||
```
|
||||
|
||||
These checks will run on GitHub Actions when you open your Pull Request, but running them locally
|
||||
@@ -72,13 +78,6 @@ after running `cargo test` like so:
|
||||
cargo insta review
|
||||
```
|
||||
|
||||
If you have `pre-commit` [installed](https://pre-commit.com/#installation) then you can use it to
|
||||
assist with formatting and linting. The following command will run the `pre-commit` hooks:
|
||||
|
||||
```shell
|
||||
pre-commit run --all-files
|
||||
```
|
||||
|
||||
Your Pull Request will be reviewed by a maintainer, which may involve a few rounds of iteration
|
||||
prior to merging.
|
||||
|
||||
@@ -93,64 +92,89 @@ The vast majority of the code, including all lint rules, lives in the `ruff` cra
|
||||
At time of writing, the repository includes the following crates:
|
||||
|
||||
- `crates/ruff`: library crate containing all lint rules and the core logic for running them.
|
||||
- `crates/ruff_benchmark`: binary crate for running micro-benchmarks.
|
||||
- `crates/ruff_cache`: library crate for caching lint results.
|
||||
- `crates/ruff_cli`: binary crate containing Ruff's command-line interface.
|
||||
- `crates/ruff_dev`: binary crate containing utilities used in the development of Ruff itself (e.g.,
|
||||
`cargo dev generate-all`).
|
||||
- `crates/ruff_diagnostics`: library crate for the lint diagnostics APIs.
|
||||
- `crates/ruff_formatter`: library crate for generic code formatting logic based on an intermediate
|
||||
representation.
|
||||
- `crates/ruff_index`: library crate inspired by `rustc_index`.
|
||||
- `crates/ruff_macros`: library crate containing macros used by Ruff.
|
||||
- `crates/ruff_python`: library crate implementing Python-specific functionality (e.g., lists of
|
||||
standard library modules by version).
|
||||
- `crates/flake8_to_ruff`: binary crate for generating Ruff configuration from Flake8 configuration.
|
||||
- `crates/ruff_python_ast`: library crate containing Python-specific AST types and utilities.
|
||||
- `crates/ruff_python_formatter`: library crate containing Python-specific code formatting logic.
|
||||
- `crates/ruff_python_semantic`: library crate containing Python-specific semantic analysis logic,
|
||||
including Ruff's semantic model.
|
||||
- `crates/ruff_python_stdlib`: library crate containing Python-specific standard library data.
|
||||
- `crates/ruff_python_whitespace`: library crate containing Python-specific whitespace analysis
|
||||
logic.
|
||||
- `crates/ruff_rustpython`: library crate containing `RustPython`-specific utilities.
|
||||
- `crates/ruff_testing_macros`: library crate containing macros used for testing Ruff.
|
||||
- `crates/ruff_textwrap`: library crate to indent and dedent Python source code.
|
||||
- `crates/ruff_wasm`: library crate for exposing Ruff as a WebAssembly module.
|
||||
|
||||
### Example: Adding a new lint rule
|
||||
|
||||
At a high level, the steps involved in adding a new lint rule are as follows:
|
||||
|
||||
1. Determine a name for the new rule as per our [rule naming convention](#rule-naming-convention).
|
||||
1. Determine a name for the new rule as per our [rule naming convention](#rule-naming-convention)
|
||||
(e.g., `AssertFalse`, as in, "allow `assert False`").
|
||||
|
||||
1. Create a file for your rule (e.g., `crates/ruff/src/rules/flake8_bugbear/rules/abstract_base_class.rs`).
|
||||
1. Create a file for your rule (e.g., `crates/ruff/src/rules/flake8_bugbear/rules/assert_false.rs`).
|
||||
|
||||
1. In that file, define a violation struct. You can grep for `#[violation]` to see examples.
|
||||
1. In that file, define a violation struct (e.g., `pub struct AssertFalse`). You can grep for
|
||||
`#[violation]` to see examples.
|
||||
|
||||
1. Map the violation struct to a rule code in `crates/ruff/src/codes.rs` (e.g., `E402`).
|
||||
1. In that file, define a function that adds the violation to the diagnostic list as appropriate
|
||||
(e.g., `pub(crate) fn assert_false`) based on whatever inputs are required for the rule (e.g.,
|
||||
an `ast::StmtAssert` node).
|
||||
|
||||
1. Define the logic for triggering the violation in `crates/ruff/src/checkers/ast/mod.rs` (for
|
||||
AST-based checks), `crates/ruff/src/checkers/tokens.rs` (for token-based checks),
|
||||
`crates/ruff/src/checkers/lines.rs` (for text-based checks), or
|
||||
`crates/ruff/src/checkers/filesystem.rs` (for filesystem-based checks).
|
||||
|
||||
1. Map the violation struct to a rule code in `crates/ruff/src/codes.rs` (e.g., `B011`).
|
||||
|
||||
1. Add proper [testing](#rule-testing-fixtures-and-snapshots) for your rule.
|
||||
|
||||
1. Update the generated files (documentation and generated code).
|
||||
|
||||
To define the violation, start by creating a dedicated file for your rule under the appropriate
|
||||
rule linter (e.g., `crates/ruff/src/rules/flake8_bugbear/rules/abstract_base_class.rs`). That file should
|
||||
contain a struct defined via `#[violation]`, along with a function that creates the violation
|
||||
based on any required inputs.
|
||||
|
||||
To trigger the violation, you'll likely want to augment the logic in `crates/ruff/src/checkers/ast.rs`,
|
||||
which defines the Python AST visitor, responsible for iterating over the abstract syntax tree and
|
||||
collecting diagnostics as it goes.
|
||||
To trigger the violation, you'll likely want to augment the logic in `crates/ruff/src/checkers/ast.rs`
|
||||
to call your new function at the appropriate time and with the appropriate inputs. The `Checker`
|
||||
defined therein is a Python AST visitor, which iterates over the AST, building up a semantic model,
|
||||
and calling out to lint rule analyzer functions as it goes.
|
||||
|
||||
If you need to inspect the AST, you can run `cargo dev print-ast` with a Python file. Grep
|
||||
for the `Check::new` invocations to understand how other, similar rules are implemented.
|
||||
for the `Diagnostic::new` invocations to understand how other, similar rules are implemented.
|
||||
|
||||
Once you're satisfied with your code, add tests for your rule. See [rule testing](#rule-testing-fixtures-and-snapshots)
|
||||
for more details.
|
||||
|
||||
Finally, regenerate the documentation and generated code with `cargo dev generate-all`.
|
||||
Finally, regenerate the documentation and other generated assets (like our JSON Schema) with:
|
||||
`cargo dev generate-all`.
|
||||
|
||||
#### Rule naming convention
|
||||
|
||||
The rule name should make sense when read as "allow _rule-name_" or "allow _rule-name_ items".
|
||||
Like Clippy, Ruff's rule names should make grammatical and logical sense when read as "allow
|
||||
${rule}" or "allow ${rule} items", as in the context of suppression comments.
|
||||
|
||||
This implies that rule names:
|
||||
For example, `AssertFalse` fits this convention: it flags `assert False` statements, and so a
|
||||
suppression comment would be framed as "allow `assert False`".
|
||||
|
||||
- should state the bad thing being checked for
|
||||
As such, rule names should...
|
||||
|
||||
- should not contain instructions on what you should use instead
|
||||
(these belong in the rule documentation and the `autofix_title` for rules that have autofix)
|
||||
- Highlight the pattern that is being linted against, rather than the preferred alternative.
|
||||
For example, `AssertFalse` guards against `assert False` statements.
|
||||
|
||||
When re-implementing rules from other linters, this convention is given more importance than
|
||||
- _Not_ contain instructions on how to fix the violation, which instead belong in the rule
|
||||
documentation and the `autofix_title`.
|
||||
|
||||
- _Not_ contain a redundant prefix, like `Disallow` or `Banned`, which are already implied by the
|
||||
convention.
|
||||
|
||||
When re-implementing rules from other linters, we prioritize adhering to this convention over
|
||||
preserving the original rule name.
|
||||
|
||||
#### Rule testing: fixtures and snapshots
|
||||
@@ -258,7 +282,7 @@ python scripts/check_ecosystem.py path/to/your/ruff path/to/older/ruff
|
||||
|
||||
You can also run the Ecosystem CI check in a Docker container across a larger set of projects by
|
||||
downloading the [`known-github-tomls.json`](https://github.com/akx/ruff-usage-aggregate/blob/master/data/known-github-tomls.jsonl)
|
||||
as `github_search.jsonl` and following the instructions in [scripts/Dockerfile.ecosystem](https://github.com/charliermarsh/ruff/blob/main/scripts/Dockerfile.ecosystem).
|
||||
as `github_search.jsonl` and following the instructions in [scripts/Dockerfile.ecosystem](https://github.com/astral-sh/ruff/blob/main/scripts/Dockerfile.ecosystem).
|
||||
Note that this check will take a while to run.
|
||||
|
||||
## Benchmarks
|
||||
|
||||
178
Cargo.lock
generated
178
Cargo.lock
generated
@@ -171,6 +171,12 @@ version = "0.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8"
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.21.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d"
|
||||
|
||||
[[package]]
|
||||
name = "bincode"
|
||||
version = "1.3.3"
|
||||
@@ -256,7 +262,8 @@ dependencies = [
|
||||
"iana-time-zone",
|
||||
"js-sys",
|
||||
"num-traits",
|
||||
"time",
|
||||
"serde",
|
||||
"time 0.1.45",
|
||||
"wasm-bindgen",
|
||||
"winapi",
|
||||
]
|
||||
@@ -555,6 +562,41 @@ dependencies = [
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "darling"
|
||||
version = "0.20.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0558d22a7b463ed0241e993f76f09f30b126687447751a8638587b864e4b3944"
|
||||
dependencies = [
|
||||
"darling_core",
|
||||
"darling_macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "darling_core"
|
||||
version = "0.20.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ab8bfa2e259f8ee1ce5e97824a3c55ec4404a0d772ca7fa96bf19f0752a046eb"
|
||||
dependencies = [
|
||||
"fnv",
|
||||
"ident_case",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"strsim",
|
||||
"syn 2.0.18",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "darling_macro"
|
||||
version = "0.20.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "29a358ff9f12ec09c3e61fef9b5a9902623a695a46a917b07f269bff1445611a"
|
||||
dependencies = [
|
||||
"darling_core",
|
||||
"quote",
|
||||
"syn 2.0.18",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "diff"
|
||||
version = "0.1.13"
|
||||
@@ -691,7 +733,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "flake8-to-ruff"
|
||||
version = "0.0.271"
|
||||
version = "0.0.272"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap",
|
||||
@@ -814,6 +856,12 @@ version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286"
|
||||
|
||||
[[package]]
|
||||
name = "hex"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
|
||||
|
||||
[[package]]
|
||||
name = "hexf-parse"
|
||||
version = "0.2.1"
|
||||
@@ -843,6 +891,12 @@ dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ident_case"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
|
||||
|
||||
[[package]]
|
||||
name = "idna"
|
||||
version = "0.3.0"
|
||||
@@ -1402,6 +1456,7 @@ version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "928c6535de93548188ef63bb7c4036bd415cd8f36ad25af44b9789b2ee72a48c"
|
||||
dependencies = [
|
||||
"phf_macros",
|
||||
"phf_shared",
|
||||
]
|
||||
|
||||
@@ -1425,6 +1480,19 @@ dependencies = [
|
||||
"rand",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "phf_macros"
|
||||
version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "92aacdc5f16768709a569e913f7451034034178b05bdc8acda226659a3dccc66"
|
||||
dependencies = [
|
||||
"phf_generator",
|
||||
"phf_shared",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "phf_shared"
|
||||
version = "0.11.1"
|
||||
@@ -1725,7 +1793,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ruff"
|
||||
version = "0.0.271"
|
||||
version = "0.0.272"
|
||||
dependencies = [
|
||||
"annotate-snippets 0.9.1",
|
||||
"anyhow",
|
||||
@@ -1752,6 +1820,7 @@ dependencies = [
|
||||
"path-absolutize",
|
||||
"pathdiff",
|
||||
"pep440_rs",
|
||||
"phf",
|
||||
"pretty_assertions",
|
||||
"pyproject-toml",
|
||||
"quick-junit",
|
||||
@@ -1760,10 +1829,10 @@ dependencies = [
|
||||
"ruff_cache",
|
||||
"ruff_diagnostics",
|
||||
"ruff_macros",
|
||||
"ruff_newlines",
|
||||
"ruff_python_ast",
|
||||
"ruff_python_semantic",
|
||||
"ruff_python_stdlib",
|
||||
"ruff_python_whitespace",
|
||||
"ruff_rustpython",
|
||||
"ruff_text_size",
|
||||
"ruff_textwrap",
|
||||
@@ -1774,6 +1843,7 @@ dependencies = [
|
||||
"semver",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_with",
|
||||
"shellexpand",
|
||||
"similar",
|
||||
"smallvec",
|
||||
@@ -1810,6 +1880,7 @@ name = "ruff_cache"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"filetime",
|
||||
"glob",
|
||||
"globset",
|
||||
"itertools",
|
||||
"regex",
|
||||
@@ -1818,7 +1889,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ruff_cli"
|
||||
version = "0.0.271"
|
||||
version = "0.0.272"
|
||||
dependencies = [
|
||||
"annotate-snippets 0.9.1",
|
||||
"anyhow",
|
||||
@@ -1837,6 +1908,7 @@ dependencies = [
|
||||
"glob",
|
||||
"ignore",
|
||||
"itertools",
|
||||
"itoa",
|
||||
"log",
|
||||
"mimalloc",
|
||||
"notify",
|
||||
@@ -1871,17 +1943,20 @@ dependencies = [
|
||||
"clap",
|
||||
"itertools",
|
||||
"libcst",
|
||||
"log",
|
||||
"once_cell",
|
||||
"pretty_assertions",
|
||||
"regex",
|
||||
"ruff",
|
||||
"ruff_cli",
|
||||
"ruff_diagnostics",
|
||||
"ruff_python_formatter",
|
||||
"ruff_textwrap",
|
||||
"rustpython-format",
|
||||
"rustpython-parser",
|
||||
"schemars",
|
||||
"serde_json",
|
||||
"similar",
|
||||
"strum",
|
||||
"strum_macros",
|
||||
]
|
||||
@@ -1930,14 +2005,6 @@ dependencies = [
|
||||
"syn 2.0.18",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ruff_newlines"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"ruff_text_size",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ruff_python_ast"
|
||||
version = "0.0.0"
|
||||
@@ -1952,7 +2019,7 @@ dependencies = [
|
||||
"num-bigint",
|
||||
"num-traits",
|
||||
"once_cell",
|
||||
"ruff_newlines",
|
||||
"ruff_python_whitespace",
|
||||
"ruff_text_size",
|
||||
"rustc-hash",
|
||||
"rustpython-ast",
|
||||
@@ -1974,8 +2041,8 @@ dependencies = [
|
||||
"itertools",
|
||||
"once_cell",
|
||||
"ruff_formatter",
|
||||
"ruff_newlines",
|
||||
"ruff_python_ast",
|
||||
"ruff_python_whitespace",
|
||||
"ruff_testing_macros",
|
||||
"ruff_text_size",
|
||||
"rustc-hash",
|
||||
@@ -2009,6 +2076,14 @@ dependencies = [
|
||||
"rustc-hash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ruff_python_whitespace"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"ruff_text_size",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ruff_rustpython"
|
||||
version = "0.0.0"
|
||||
@@ -2030,7 +2105,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "ruff_text_size"
|
||||
version = "0.0.0"
|
||||
source = "git+https://github.com/astral-sh/RustPython-Parser.git?rev=7a3eedbf6fb4ea7068a1bf7fe0e97e963ea95ffd#7a3eedbf6fb4ea7068a1bf7fe0e97e963ea95ffd"
|
||||
source = "git+https://github.com/astral-sh/RustPython-Parser.git?rev=8d74eee75031b68d2204219963fae54a3f31a394#8d74eee75031b68d2204219963fae54a3f31a394"
|
||||
dependencies = [
|
||||
"schemars",
|
||||
"serde",
|
||||
@@ -2040,7 +2115,7 @@ dependencies = [
|
||||
name = "ruff_textwrap"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"ruff_newlines",
|
||||
"ruff_python_whitespace",
|
||||
"ruff_text_size",
|
||||
]
|
||||
|
||||
@@ -2108,7 +2183,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "rustpython-ast"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/astral-sh/RustPython-Parser.git?rev=7a3eedbf6fb4ea7068a1bf7fe0e97e963ea95ffd#7a3eedbf6fb4ea7068a1bf7fe0e97e963ea95ffd"
|
||||
source = "git+https://github.com/astral-sh/RustPython-Parser.git?rev=8d74eee75031b68d2204219963fae54a3f31a394#8d74eee75031b68d2204219963fae54a3f31a394"
|
||||
dependencies = [
|
||||
"is-macro",
|
||||
"num-bigint",
|
||||
@@ -2119,7 +2194,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "rustpython-format"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/astral-sh/RustPython-Parser.git?rev=7a3eedbf6fb4ea7068a1bf7fe0e97e963ea95ffd#7a3eedbf6fb4ea7068a1bf7fe0e97e963ea95ffd"
|
||||
source = "git+https://github.com/astral-sh/RustPython-Parser.git?rev=8d74eee75031b68d2204219963fae54a3f31a394#8d74eee75031b68d2204219963fae54a3f31a394"
|
||||
dependencies = [
|
||||
"bitflags 2.3.1",
|
||||
"itertools",
|
||||
@@ -2131,7 +2206,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "rustpython-literal"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/astral-sh/RustPython-Parser.git?rev=7a3eedbf6fb4ea7068a1bf7fe0e97e963ea95ffd#7a3eedbf6fb4ea7068a1bf7fe0e97e963ea95ffd"
|
||||
source = "git+https://github.com/astral-sh/RustPython-Parser.git?rev=8d74eee75031b68d2204219963fae54a3f31a394#8d74eee75031b68d2204219963fae54a3f31a394"
|
||||
dependencies = [
|
||||
"hexf-parse",
|
||||
"is-macro",
|
||||
@@ -2143,7 +2218,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "rustpython-parser"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/astral-sh/RustPython-Parser.git?rev=7a3eedbf6fb4ea7068a1bf7fe0e97e963ea95ffd#7a3eedbf6fb4ea7068a1bf7fe0e97e963ea95ffd"
|
||||
source = "git+https://github.com/astral-sh/RustPython-Parser.git?rev=8d74eee75031b68d2204219963fae54a3f31a394#8d74eee75031b68d2204219963fae54a3f31a394"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"is-macro",
|
||||
@@ -2166,9 +2241,10 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "rustpython-parser-core"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/astral-sh/RustPython-Parser.git?rev=7a3eedbf6fb4ea7068a1bf7fe0e97e963ea95ffd#7a3eedbf6fb4ea7068a1bf7fe0e97e963ea95ffd"
|
||||
source = "git+https://github.com/astral-sh/RustPython-Parser.git?rev=8d74eee75031b68d2204219963fae54a3f31a394#8d74eee75031b68d2204219963fae54a3f31a394"
|
||||
dependencies = [
|
||||
"is-macro",
|
||||
"memchr",
|
||||
"ruff_text_size",
|
||||
]
|
||||
|
||||
@@ -2293,7 +2369,6 @@ version = "1.0.96"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "057d394a50403bcac12672b2b18fb387ab6d289d957dab67dd201875391e52f1"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"itoa",
|
||||
"ryu",
|
||||
"serde",
|
||||
@@ -2308,6 +2383,34 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_with"
|
||||
version = "3.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9f02d8aa6e3c385bf084924f660ce2a3a6bd333ba55b35e8590b321f35d88513"
|
||||
dependencies = [
|
||||
"base64 0.21.2",
|
||||
"chrono",
|
||||
"hex",
|
||||
"indexmap",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_with_macros",
|
||||
"time 0.3.21",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_with_macros"
|
||||
version = "3.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "edc7d5d3932fb12ce722ee5e64dd38c504efba37567f0c402f6ca728c3b8b070"
|
||||
dependencies = [
|
||||
"darling",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.18",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "shellexpand"
|
||||
version = "3.1.0"
|
||||
@@ -2534,6 +2637,33 @@ dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.3.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f3403384eaacbca9923fa06940178ac13e4edb725486d70e8e15881d0c836cc"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"serde",
|
||||
"time-core",
|
||||
"time-macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time-core"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb"
|
||||
|
||||
[[package]]
|
||||
name = "time-macros"
|
||||
version = "0.2.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "372950940a5f07bf38dbe211d7283c9e6d7327df53794992d293e534c733d09b"
|
||||
dependencies = [
|
||||
"time-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tiny-keccak"
|
||||
version = "2.0.2"
|
||||
@@ -2752,7 +2882,7 @@ version = "2.6.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "338b31dd1314f68f3aabf3ed57ab922df95ffcd902476ca7ba3c4ce7b908c46d"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"base64 0.13.1",
|
||||
"flate2",
|
||||
"log",
|
||||
"once_cell",
|
||||
|
||||
22
Cargo.toml
22
Cargo.toml
@@ -1,13 +1,15 @@
|
||||
[workspace]
|
||||
members = ["crates/*"]
|
||||
resolver = "2"
|
||||
|
||||
[workspace.package]
|
||||
edition = "2021"
|
||||
rust-version = "1.70"
|
||||
homepage = "https://beta.ruff.rs/docs/"
|
||||
documentation = "https://beta.ruff.rs/docs/"
|
||||
repository = "https://github.com/charliermarsh/ruff"
|
||||
homepage = "https://beta.ruff.rs/docs"
|
||||
documentation = "https://beta.ruff.rs/docs"
|
||||
repository = "https://github.com/astral-sh/ruff"
|
||||
authors = ["Charlie Marsh <charlie.r.marsh@gmail.com>"]
|
||||
license = "MIT"
|
||||
|
||||
[workspace.dependencies]
|
||||
anyhow = { version = "1.0.69" }
|
||||
@@ -34,16 +36,16 @@ proc-macro2 = { version = "1.0.51" }
|
||||
quote = { version = "1.0.23" }
|
||||
regex = { version = "1.7.1" }
|
||||
rustc-hash = { version = "1.1.0" }
|
||||
ruff_text_size = { git = "https://github.com/astral-sh/RustPython-Parser.git", rev = "7a3eedbf6fb4ea7068a1bf7fe0e97e963ea95ffd" }
|
||||
rustpython-ast = { git = "https://github.com/astral-sh/RustPython-Parser.git", rev = "7a3eedbf6fb4ea7068a1bf7fe0e97e963ea95ffd", default-features = false, features = ["all-nodes-with-ranges"]}
|
||||
rustpython-format = { git = "https://github.com/astral-sh/RustPython-Parser.git", rev = "7a3eedbf6fb4ea7068a1bf7fe0e97e963ea95ffd" }
|
||||
rustpython-literal = { git = "https://github.com/astral-sh/RustPython-Parser.git", rev = "7a3eedbf6fb4ea7068a1bf7fe0e97e963ea95ffd" }
|
||||
rustpython-parser = { git = "https://github.com/astral-sh/RustPython-Parser.git", rev = "7a3eedbf6fb4ea7068a1bf7fe0e97e963ea95ffd", default-features = false, features = ["full-lexer", "all-nodes-with-ranges"] }
|
||||
ruff_text_size = { git = "https://github.com/astral-sh/RustPython-Parser.git", rev = "8d74eee75031b68d2204219963fae54a3f31a394" }
|
||||
rustpython-ast = { git = "https://github.com/astral-sh/RustPython-Parser.git", rev = "8d74eee75031b68d2204219963fae54a3f31a394" , default-features = false, features = ["all-nodes-with-ranges", "num-bigint"]}
|
||||
rustpython-format = { git = "https://github.com/astral-sh/RustPython-Parser.git", rev = "8d74eee75031b68d2204219963fae54a3f31a394", default-features = false, features = ["num-bigint"] }
|
||||
rustpython-literal = { git = "https://github.com/astral-sh/RustPython-Parser.git", rev = "8d74eee75031b68d2204219963fae54a3f31a394" }
|
||||
rustpython-parser = { git = "https://github.com/astral-sh/RustPython-Parser.git", rev = "8d74eee75031b68d2204219963fae54a3f31a394" , default-features = false, features = ["full-lexer", "all-nodes-with-ranges", "num-bigint"] }
|
||||
schemars = { version = "0.8.12" }
|
||||
serde = { version = "1.0.152", features = ["derive"] }
|
||||
serde_json = { version = "1.0.93", features = ["preserve_order"] }
|
||||
serde_json = { version = "1.0.93" }
|
||||
shellexpand = { version = "3.0.0" }
|
||||
similar = { version = "2.2.1" }
|
||||
similar = { version = "2.2.1", features = ["inline"] }
|
||||
smallvec = { version = "1.10.0" }
|
||||
strum = { version = "0.24.1", features = ["strum_macros"] }
|
||||
strum_macros = { version = "0.24.3" }
|
||||
|
||||
48
LICENSE
48
LICENSE
@@ -354,6 +354,29 @@ are:
|
||||
SOFTWARE.
|
||||
"""
|
||||
|
||||
- flake8-slots, licensed as follows:
|
||||
"""
|
||||
Copyright (c) 2021 Dominic Davis-Foster
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
|
||||
OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
"""
|
||||
|
||||
- flake8-todos, licensed as follows:
|
||||
"""
|
||||
Copyright (c) 2019 EclecticIQ. All rights reserved.
|
||||
@@ -1176,6 +1199,31 @@ are:
|
||||
|
||||
- flake8-django, licensed under the GPL license.
|
||||
|
||||
- perflint, licensed as follows:
|
||||
"""
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2022 Anthony Shaw
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
"""
|
||||
|
||||
- rust-analyzer/text-size, licensed under the MIT license:
|
||||
"""
|
||||
Permission is hereby granted, free of charge, to any
|
||||
|
||||
26
README.md
26
README.md
@@ -2,11 +2,11 @@
|
||||
|
||||
# Ruff
|
||||
|
||||
[](https://github.com/charliermarsh/ruff)
|
||||
[](https://github.com/astral-sh/ruff)
|
||||
[](https://pypi.python.org/pypi/ruff)
|
||||
[](https://pypi.python.org/pypi/ruff)
|
||||
[](https://pypi.python.org/pypi/ruff)
|
||||
[](https://github.com/charliermarsh/ruff/actions)
|
||||
[](https://github.com/astral-sh/ruff/actions)
|
||||
|
||||
[**Discord**](https://discord.gg/c9MhzV8aU5) | [**Docs**](https://beta.ruff.rs/docs/) | [**Playground**](https://play.ruff.rs/)
|
||||
|
||||
@@ -88,7 +88,7 @@ creator of [isort](https://github.com/PyCQA/isort):
|
||||
> Just switched my first project to Ruff. Only one downside so far: it's so fast I couldn't believe
|
||||
> it was working till I intentionally introduced some errors.
|
||||
|
||||
[**Tim Abbott**](https://github.com/charliermarsh/ruff/issues/465#issuecomment-1317400028), lead
|
||||
[**Tim Abbott**](https://github.com/astral-sh/ruff/issues/465#issuecomment-1317400028), lead
|
||||
developer of [Zulip](https://github.com/zulip/zulip):
|
||||
|
||||
> This is just ridiculously fast... `ruff` is amazing.
|
||||
@@ -139,7 +139,7 @@ Ruff can also be used as a [pre-commit](https://pre-commit.com) hook:
|
||||
```yaml
|
||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||
# Ruff version.
|
||||
rev: v0.0.271
|
||||
rev: v0.0.272
|
||||
hooks:
|
||||
- id: ruff
|
||||
```
|
||||
@@ -254,13 +254,14 @@ quality tools, including:
|
||||
- [flake8-2020](https://pypi.org/project/flake8-2020/)
|
||||
- [flake8-annotations](https://pypi.org/project/flake8-annotations/)
|
||||
- [flake8-async](https://pypi.org/project/flake8-async)
|
||||
- [flake8-bandit](https://pypi.org/project/flake8-bandit/) ([#1646](https://github.com/charliermarsh/ruff/issues/1646))
|
||||
- [flake8-bandit](https://pypi.org/project/flake8-bandit/) ([#1646](https://github.com/astral-sh/ruff/issues/1646))
|
||||
- [flake8-blind-except](https://pypi.org/project/flake8-blind-except/)
|
||||
- [flake8-boolean-trap](https://pypi.org/project/flake8-boolean-trap/)
|
||||
- [flake8-bugbear](https://pypi.org/project/flake8-bugbear/)
|
||||
- [flake8-builtins](https://pypi.org/project/flake8-builtins/)
|
||||
- [flake8-commas](https://pypi.org/project/flake8-commas/)
|
||||
- [flake8-comprehensions](https://pypi.org/project/flake8-comprehensions/)
|
||||
- [flake8-copyright](https://pypi.org/project/flake8-copyright/)
|
||||
- [flake8-datetimez](https://pypi.org/project/flake8-datetimez/)
|
||||
- [flake8-debugger](https://pypi.org/project/flake8-debugger/)
|
||||
- [flake8-django](https://pypi.org/project/flake8-django/)
|
||||
@@ -283,12 +284,13 @@ quality tools, including:
|
||||
- [flake8-return](https://pypi.org/project/flake8-return/)
|
||||
- [flake8-self](https://pypi.org/project/flake8-self/)
|
||||
- [flake8-simplify](https://pypi.org/project/flake8-simplify/)
|
||||
- [flake8-slots](https://pypi.org/project/flake8-slots/)
|
||||
- [flake8-super](https://pypi.org/project/flake8-super/)
|
||||
- [flake8-tidy-imports](https://pypi.org/project/flake8-tidy-imports/)
|
||||
- [flake8-todos](https://pypi.org/project/flake8-todos/)
|
||||
- [flake8-type-checking](https://pypi.org/project/flake8-type-checking/)
|
||||
- [flake8-use-pathlib](https://pypi.org/project/flake8-use-pathlib/)
|
||||
- [flynt](https://pypi.org/project/flynt/) ([#2102](https://github.com/charliermarsh/ruff/issues/2102))
|
||||
- [flynt](https://pypi.org/project/flynt/) ([#2102](https://github.com/astral-sh/ruff/issues/2102))
|
||||
- [isort](https://pypi.org/project/isort/)
|
||||
- [mccabe](https://pypi.org/project/mccabe/)
|
||||
- [pandas-vet](https://pypi.org/project/pandas-vet/)
|
||||
@@ -311,8 +313,8 @@ You can also join us on [**Discord**](https://discord.gg/c9MhzV8aU5).
|
||||
|
||||
## Support
|
||||
|
||||
Having trouble? Check out the existing issues on [**GitHub**](https://github.com/charliermarsh/ruff/issues),
|
||||
or feel free to [**open a new one**](https://github.com/charliermarsh/ruff/issues/new).
|
||||
Having trouble? Check out the existing issues on [**GitHub**](https://github.com/astral-sh/ruff/issues),
|
||||
or feel free to [**open a new one**](https://github.com/astral-sh/ruff/issues/new).
|
||||
|
||||
You can also ask for help on [**Discord**](https://discord.gg/c9MhzV8aU5).
|
||||
|
||||
@@ -334,7 +336,7 @@ and again draws on both the APIs and implementation details of [Rome](https://gi
|
||||
Ruff is also influenced by a number of tools outside the Python ecosystem, like
|
||||
[Clippy](https://github.com/rust-lang/rust-clippy) and [ESLint](https://github.com/eslint/eslint).
|
||||
|
||||
Ruff is the beneficiary of a large number of [contributors](https://github.com/charliermarsh/ruff/graphs/contributors).
|
||||
Ruff is the beneficiary of a large number of [contributors](https://github.com/astral-sh/ruff/graphs/contributors).
|
||||
|
||||
Ruff is released under the MIT license.
|
||||
|
||||
@@ -413,21 +415,21 @@ Ruff is used by a number of major open-source projects and companies, including:
|
||||
If you're using Ruff, consider adding the Ruff badge to project's `README.md`:
|
||||
|
||||
```md
|
||||
[](https://github.com/charliermarsh/ruff)
|
||||
[](https://github.com/astral-sh/ruff)
|
||||
```
|
||||
|
||||
...or `README.rst`:
|
||||
|
||||
```rst
|
||||
.. image:: https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/charliermarsh/ruff/main/assets/badge/v2.json
|
||||
:target: https://github.com/charliermarsh/ruff
|
||||
:target: https://github.com/astral-sh/ruff
|
||||
:alt: Ruff
|
||||
```
|
||||
|
||||
...or, as HTML:
|
||||
|
||||
```html
|
||||
<a href="https://github.com/charliermarsh/ruff"><img src="https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/charliermarsh/ruff/main/assets/badge/v2.json" alt="Ruff" style="max-width:100%;"></a>
|
||||
<a href="https://github.com/astral-sh/ruff"><img src="https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/charliermarsh/ruff/main/assets/badge/v2.json" alt="Ruff" style="max-width:100%;"></a>
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
@@ -8,3 +8,4 @@ whos = "whos"
|
||||
spawnve = "spawnve"
|
||||
ned = "ned"
|
||||
poit = "poit"
|
||||
BA = "BA" # acronym for "Bad Allowed", used in testing.
|
||||
|
||||
BIN
assets/png/Astral.png
Normal file
BIN
assets/png/Astral.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.8 KiB |
@@ -1,8 +1,16 @@
|
||||
[package]
|
||||
name = "flake8-to-ruff"
|
||||
version = "0.0.271"
|
||||
version = "0.0.272"
|
||||
description = """
|
||||
Convert Flake8 configuration files to Ruff configuration files.
|
||||
"""
|
||||
authors = { workspace = true }
|
||||
edition = { workspace = true }
|
||||
rust-version = { workspace = true }
|
||||
homepage = { workspace = true }
|
||||
documentation = { workspace = true }
|
||||
repository = { workspace = true }
|
||||
license = { workspace = true }
|
||||
|
||||
[dependencies]
|
||||
ruff = { path = "../ruff", default-features = false }
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# flake8-to-ruff
|
||||
|
||||
Convert existing Flake8 configuration files (`setup.cfg`, `tox.ini`, or `.flake8`) for use with
|
||||
[Ruff](https://github.com/charliermarsh/ruff).
|
||||
[Ruff](https://github.com/astral-sh/ruff).
|
||||
|
||||
Generates a Ruff-compatible `pyproject.toml` section.
|
||||
|
||||
@@ -96,4 +96,4 @@ MIT
|
||||
## Contributing
|
||||
|
||||
Contributions are welcome and hugely appreciated. To get started, check out the
|
||||
[contributing guidelines](https://github.com/charliermarsh/ruff/blob/main/CONTRIBUTING.md).
|
||||
[contributing guidelines](https://github.com/astral-sh/ruff/blob/main/CONTRIBUTING.md).
|
||||
|
||||
@@ -23,7 +23,7 @@ description = "Convert existing Flake8 configuration to Ruff."
|
||||
requires-python = ">=3.7"
|
||||
|
||||
[project.urls]
|
||||
repository = "https://github.com/charliermarsh/ruff#subdirectory=crates/flake8_to_ruff"
|
||||
repository = "https://github.com/astral-sh/ruff#subdirectory=crates/flake8_to_ruff"
|
||||
|
||||
[build-system]
|
||||
requires = ["maturin>=1.0,<2.0"]
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
[package]
|
||||
name = "ruff"
|
||||
version = "0.0.271"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
rust-version.workspace = true
|
||||
documentation.workspace = true
|
||||
homepage.workspace = true
|
||||
repository.workspace = true
|
||||
version = "0.0.272"
|
||||
publish = false
|
||||
authors = { workspace = true }
|
||||
edition = { workspace = true }
|
||||
rust-version = { workspace = true }
|
||||
homepage = { workspace = true }
|
||||
documentation = { workspace = true }
|
||||
repository = { workspace = true }
|
||||
license = { workspace = true }
|
||||
readme = "README.md"
|
||||
license = "MIT"
|
||||
|
||||
[lib]
|
||||
name = "ruff"
|
||||
@@ -17,7 +18,7 @@ name = "ruff"
|
||||
ruff_cache = { path = "../ruff_cache" }
|
||||
ruff_diagnostics = { path = "../ruff_diagnostics", features = ["serde"] }
|
||||
ruff_macros = { path = "../ruff_macros" }
|
||||
ruff_newlines = { path = "../ruff_newlines" }
|
||||
ruff_python_whitespace = { path = "../ruff_python_whitespace" }
|
||||
ruff_python_ast = { path = "../ruff_python_ast", features = ["serde"] }
|
||||
ruff_python_semantic = { path = "../ruff_python_semantic" }
|
||||
ruff_python_stdlib = { path = "../ruff_python_stdlib" }
|
||||
@@ -52,6 +53,7 @@ path-absolutize = { workspace = true, features = [
|
||||
] }
|
||||
pathdiff = { version = "0.2.1" }
|
||||
pep440_rs = { version = "0.3.1", features = ["serde"] }
|
||||
phf = { version = "0.11", features = ["macros"] }
|
||||
pyproject-toml = { version = "0.6.0" }
|
||||
quick-junit = { version = "0.3.2" }
|
||||
regex = { workspace = true }
|
||||
@@ -63,7 +65,8 @@ schemars = { workspace = true, optional = true }
|
||||
semver = { version = "1.0.16" }
|
||||
serde = { workspace = true }
|
||||
serde_json = { workspace = true }
|
||||
similar = { workspace = true, features = ["inline"] }
|
||||
serde_with = { version = "3.0.0" }
|
||||
similar = { workspace = true }
|
||||
shellexpand = { workspace = true }
|
||||
smallvec = { workspace = true }
|
||||
strum = { workspace = true }
|
||||
|
||||
@@ -149,7 +149,7 @@ for group in groupby(items, key=lambda p: p[1]):
|
||||
collect_shop_items("Joe", group[1])
|
||||
|
||||
|
||||
# https://github.com/charliermarsh/ruff/issues/4050
|
||||
# https://github.com/astral-sh/ruff/issues/4050
|
||||
for _section, section_items in itertools.groupby(items, key=lambda p: p[1]):
|
||||
if _section == "greens":
|
||||
for item in section_items:
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
from itertools import count, cycle, repeat
|
||||
|
||||
# Errors
|
||||
zip()
|
||||
zip(range(3))
|
||||
zip("a", "b")
|
||||
@@ -5,6 +8,18 @@ zip("a", "b", *zip("c"))
|
||||
zip(zip("a"), strict=False)
|
||||
zip(zip("a", strict=True))
|
||||
|
||||
# OK
|
||||
zip(range(3), strict=True)
|
||||
zip("a", "b", strict=False)
|
||||
zip("a", "b", "c", strict=True)
|
||||
|
||||
# OK (infinite iterators).
|
||||
zip([1, 2, 3], cycle("ABCDEF"))
|
||||
zip([1, 2, 3], count())
|
||||
zip([1, 2, 3], repeat(1))
|
||||
zip([1, 2, 3], repeat(1, None))
|
||||
zip([1, 2, 3], repeat(1, times=None))
|
||||
|
||||
# Errors (limited iterators).
|
||||
zip([1, 2, 3], repeat(1, 1))
|
||||
zip([1, 2, 3], repeat(1, times=4))
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
class MyClass:
|
||||
ImportError = 4
|
||||
id = 5
|
||||
id: int
|
||||
dir = "/"
|
||||
|
||||
def __init__(self):
|
||||
@@ -10,3 +10,10 @@ class MyClass:
|
||||
|
||||
def str(self):
|
||||
pass
|
||||
|
||||
|
||||
from typing import TypedDict
|
||||
|
||||
|
||||
class MyClass(TypedDict):
|
||||
id: int
|
||||
|
||||
@@ -1,13 +1,20 @@
|
||||
x = set(x for x in range(3))
|
||||
x = set(
|
||||
x for x in range(3)
|
||||
)
|
||||
y = f'{set(a if a < 6 else 0 for a in range(3))}'
|
||||
_ = '{}'.format(set(a if a < 6 else 0 for a in range(3)))
|
||||
print(f'Hello {set(a for a in range(3))} World')
|
||||
|
||||
def set(*args, **kwargs):
|
||||
return None
|
||||
x = set(x for x in range(3))
|
||||
y = f"{set(a if a < 6 else 0 for a in range(3))}"
|
||||
_ = "{}".format(set(a if a < 6 else 0 for a in range(3)))
|
||||
print(f"Hello {set(a for a in range(3))} World")
|
||||
|
||||
|
||||
set(x for x in range(3))
|
||||
def f(x):
|
||||
return x
|
||||
|
||||
|
||||
print(f'Hello {set(a for a in "abc")} World')
|
||||
print(f"Hello {set(a for a in 'abc')} World")
|
||||
print(f"Hello {set(f(a) for a in 'abc')} World")
|
||||
print(f"{set(a for a in 'abc') - set(a for a in 'ab')}")
|
||||
print(f"{ set(a for a in 'abc') - set(a for a in 'ab') }")
|
||||
|
||||
# The fix generated for this diagnostic is incorrect, as we add additional space
|
||||
# around the set comprehension.
|
||||
print(f"{ {set(a for a in 'abc')} }")
|
||||
|
||||
@@ -5,3 +5,14 @@ dict(
|
||||
dict(((x, x) for x in range(3)), z=3)
|
||||
y = f'{dict((x, x) for x in range(3))}'
|
||||
print(f'Hello {dict((x, x) for x in range(3))} World')
|
||||
print(f"Hello {dict((x, x) for x in 'abc')} World")
|
||||
print(f'Hello {dict((x, x) for x in "abc")} World')
|
||||
print(f'Hello {dict((x,x) for x in "abc")} World')
|
||||
|
||||
f'{dict((x, x) for x in range(3)) | dict((x, x) for x in range(3))}'
|
||||
f'{ dict((x, x) for x in range(3)) | dict((x, x) for x in range(3)) }'
|
||||
|
||||
def f(x):
|
||||
return x
|
||||
|
||||
print(f'Hello {dict((x,f(x)) for x in "abc")} World')
|
||||
|
||||
@@ -2,3 +2,14 @@ s = set([x for x in range(3)])
|
||||
s = set(
|
||||
[x for x in range(3)]
|
||||
)
|
||||
|
||||
s = f"{set([x for x in 'ab'])}"
|
||||
s = f'{set([x for x in "ab"])}'
|
||||
|
||||
def f(x):
|
||||
return x
|
||||
|
||||
s = f"{set([f(x) for x in 'ab'])}"
|
||||
|
||||
s = f"{ set([x for x in 'ab']) | set([x for x in 'ab']) }"
|
||||
s = f"{set([x for x in 'ab']) | set([x for x in 'ab'])}"
|
||||
|
||||
@@ -1,2 +1,13 @@
|
||||
dict([(i, i) for i in range(3)])
|
||||
dict([(i, i) for i in range(3)], z=4)
|
||||
|
||||
def f(x):
|
||||
return x
|
||||
|
||||
f'{dict([(s,s) for s in "ab"])}'
|
||||
f"{dict([(s,s) for s in 'ab'])}"
|
||||
f"{dict([(s, s) for s in 'ab'])}"
|
||||
f"{dict([(s,f(s)) for s in 'ab'])}"
|
||||
|
||||
f'{dict([(s,s) for s in "ab"]) | dict([(s,s) for s in "ab"])}'
|
||||
f'{ dict([(s,s) for s in "ab"]) | dict([(s,s) for s in "ab"]) }'
|
||||
|
||||
@@ -16,3 +16,11 @@ set(
|
||||
set(
|
||||
[1,]
|
||||
)
|
||||
f"{set([1,2,3])}"
|
||||
f"{set(['a', 'b'])}"
|
||||
f'{set(["a", "b"])}'
|
||||
|
||||
f"{set(['a', 'b']) - set(['a'])}"
|
||||
f"{ set(['a', 'b']) - set(['a']) }"
|
||||
f"a {set(['a', 'b']) - set(['a'])} b"
|
||||
f"a { set(['a', 'b']) - set(['a']) } b"
|
||||
|
||||
@@ -10,3 +10,13 @@ def list():
|
||||
|
||||
|
||||
a = list()
|
||||
|
||||
f"{dict(x='y')}"
|
||||
f'{dict(x="y")}'
|
||||
f"{dict()}"
|
||||
f"a {dict()} b"
|
||||
|
||||
f"{dict(x='y') | dict(y='z')}"
|
||||
f"{ dict(x='y') | dict(y='z') }"
|
||||
f"a {dict(x='y') | dict(y='z')} b"
|
||||
f"a { dict(x='y') | dict(y='z') } b"
|
||||
|
||||
@@ -34,3 +34,19 @@ _ = (
|
||||
b"abc"
|
||||
b"def"
|
||||
)
|
||||
|
||||
_ = """a""" """b"""
|
||||
|
||||
_ = """a
|
||||
b""" """c
|
||||
d"""
|
||||
|
||||
_ = f"""a""" f"""b"""
|
||||
|
||||
_ = f"a" "b"
|
||||
|
||||
_ = """a""" "b"
|
||||
|
||||
_ = 'a' "b"
|
||||
|
||||
_ = rf"a" rf"b"
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
from collections.abc import Set as AbstractSet # Ok
|
||||
def f():
|
||||
from collections.abc import Set as AbstractSet # Ok
|
||||
|
||||
|
||||
from collections.abc import Set # Ok
|
||||
def f():
|
||||
from collections.abc import Container, Sized, Set as AbstractSet, ValuesView # Ok
|
||||
|
||||
|
||||
from collections.abc import (
|
||||
Container,
|
||||
Sized,
|
||||
Set, # Ok
|
||||
ValuesView
|
||||
)
|
||||
def f():
|
||||
from collections.abc import Set # PYI025
|
||||
|
||||
from collections.abc import (
|
||||
Container,
|
||||
Sized,
|
||||
Set as AbstractSet, # Ok
|
||||
ValuesView
|
||||
)
|
||||
|
||||
def f():
|
||||
from collections.abc import Container, Sized, Set, ValuesView # PYI025
|
||||
|
||||
GLOBAL: Set[int] = set()
|
||||
|
||||
class Class:
|
||||
member: Set[int]
|
||||
|
||||
@@ -1,19 +1,50 @@
|
||||
from collections.abc import Set as AbstractSet # Ok
|
||||
def f():
|
||||
from collections.abc import Set as AbstractSet # Ok
|
||||
|
||||
def f():
|
||||
from collections.abc import Container, Sized, Set as AbstractSet, ValuesView # Ok
|
||||
|
||||
from collections.abc import Set # PYI025
|
||||
def f():
|
||||
from collections.abc import Set # PYI025
|
||||
|
||||
def f():
|
||||
from collections.abc import Container, Sized, Set, ValuesView # PYI025
|
||||
|
||||
from collections.abc import (
|
||||
Container,
|
||||
Sized,
|
||||
Set, # PYI025
|
||||
ValuesView
|
||||
)
|
||||
def f():
|
||||
"""Test: local symbol renaming."""
|
||||
if True:
|
||||
from collections.abc import Set
|
||||
else:
|
||||
Set = 1
|
||||
|
||||
from collections.abc import (
|
||||
Container,
|
||||
Sized,
|
||||
Set as AbstractSet,
|
||||
ValuesView # Ok
|
||||
)
|
||||
x: Set = set()
|
||||
|
||||
x: Set
|
||||
|
||||
del Set
|
||||
|
||||
def f():
|
||||
print(Set)
|
||||
|
||||
def Set():
|
||||
pass
|
||||
print(Set)
|
||||
|
||||
from collections.abc import Set
|
||||
|
||||
def f():
|
||||
"""Test: global symbol renaming."""
|
||||
global Set
|
||||
|
||||
Set = 1
|
||||
print(Set)
|
||||
|
||||
def f():
|
||||
"""Test: nonlocal symbol renaming."""
|
||||
from collections.abc import Set
|
||||
|
||||
def g():
|
||||
nonlocal Set
|
||||
|
||||
Set = 1
|
||||
print(Set)
|
||||
|
||||
7
crates/ruff/resources/test/fixtures/flake8_pyi/PYI044.py
vendored
Normal file
7
crates/ruff/resources/test/fixtures/flake8_pyi/PYI044.py
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
# Bad import.
|
||||
from __future__ import annotations # Not PYI044 (not a stubfile).
|
||||
|
||||
# Good imports.
|
||||
from __future__ import Something
|
||||
import sys
|
||||
from socket import AF_INET
|
||||
7
crates/ruff/resources/test/fixtures/flake8_pyi/PYI044.pyi
vendored
Normal file
7
crates/ruff/resources/test/fixtures/flake8_pyi/PYI044.pyi
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
# Bad import.
|
||||
from __future__ import annotations # PYI044.
|
||||
|
||||
# Good imports.
|
||||
from __future__ import Something
|
||||
import sys
|
||||
from socket import AF_INET
|
||||
32
crates/ruff/resources/test/fixtures/flake8_pyi/PYI050.py
vendored
Normal file
32
crates/ruff/resources/test/fixtures/flake8_pyi/PYI050.py
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
from typing import NoReturn, Never
|
||||
import typing_extensions
|
||||
|
||||
|
||||
def foo(arg):
|
||||
...
|
||||
|
||||
|
||||
def foo_int(arg: int):
|
||||
...
|
||||
|
||||
|
||||
def foo_no_return(arg: NoReturn):
|
||||
...
|
||||
|
||||
|
||||
def foo_no_return_typing_extensions(
|
||||
arg: typing_extensions.NoReturn,
|
||||
):
|
||||
...
|
||||
|
||||
|
||||
def foo_no_return_kwarg(arg: int, *, arg2: NoReturn):
|
||||
...
|
||||
|
||||
|
||||
def foo_no_return_pos_only(arg: int, /, arg2: NoReturn):
|
||||
...
|
||||
|
||||
|
||||
def foo_never(arg: Never):
|
||||
...
|
||||
12
crates/ruff/resources/test/fixtures/flake8_pyi/PYI050.pyi
vendored
Normal file
12
crates/ruff/resources/test/fixtures/flake8_pyi/PYI050.pyi
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
from typing import NoReturn, Never
|
||||
import typing_extensions
|
||||
|
||||
def foo(arg): ...
|
||||
def foo_int(arg: int): ...
|
||||
def foo_no_return(arg: NoReturn): ... # Error: PYI050
|
||||
def foo_no_return_typing_extensions(
|
||||
arg: typing_extensions.NoReturn,
|
||||
): ... # Error: PYI050
|
||||
def foo_no_return_kwarg(arg: int, *, arg2: NoReturn): ... # Error: PYI050
|
||||
def foo_no_return_pos_only(arg: int, /, arg2: NoReturn): ... # Error: PYI050
|
||||
def foo_never(arg: Never): ...
|
||||
@@ -1,17 +1,25 @@
|
||||
import pytest
|
||||
|
||||
|
||||
def test_xxx():
|
||||
pytest.fail("this is a failure") # Test OK arg
|
||||
# OK
|
||||
def f():
|
||||
pytest.fail("this is a failure")
|
||||
|
||||
|
||||
def test_xxx():
|
||||
pytest.fail(msg="this is a failure") # Test OK kwarg
|
||||
def f():
|
||||
pytest.fail(msg="this is a failure")
|
||||
|
||||
|
||||
def test_xxx(): # Error
|
||||
def f():
|
||||
pytest.fail(reason="this is a failure")
|
||||
|
||||
|
||||
# Errors
|
||||
def f():
|
||||
pytest.fail()
|
||||
pytest.fail("")
|
||||
pytest.fail(f"")
|
||||
pytest.fail(msg="")
|
||||
pytest.fail(msg=f"")
|
||||
pytest.fail(reason="")
|
||||
pytest.fail(reason=f"")
|
||||
|
||||
@@ -79,7 +79,7 @@ def x():
|
||||
return a
|
||||
|
||||
|
||||
# ignore unpacking
|
||||
# Ignore unpacking
|
||||
def x():
|
||||
b, a = [1, 2]
|
||||
return a
|
||||
@@ -109,7 +109,8 @@ def x():
|
||||
|
||||
# Considered OK, since functions can have side effects.
|
||||
def x():
|
||||
b, a = 1, 2
|
||||
a = 1
|
||||
b = 2
|
||||
print(b)
|
||||
return a
|
||||
|
||||
@@ -276,20 +277,25 @@ def str_to_bool(val):
|
||||
|
||||
# Mixed assignments
|
||||
def function_assignment(x):
|
||||
def f(): ...
|
||||
def f():
|
||||
...
|
||||
|
||||
return f
|
||||
|
||||
|
||||
def class_assignment(x):
|
||||
class Foo: ...
|
||||
class Foo:
|
||||
...
|
||||
|
||||
return Foo
|
||||
|
||||
|
||||
def mixed_function_assignment(x):
|
||||
if x:
|
||||
def f(): ...
|
||||
|
||||
def f():
|
||||
...
|
||||
|
||||
else:
|
||||
f = 42
|
||||
|
||||
@@ -298,8 +304,56 @@ def mixed_function_assignment(x):
|
||||
|
||||
def mixed_class_assignment(x):
|
||||
if x:
|
||||
class Foo: ...
|
||||
|
||||
class Foo:
|
||||
...
|
||||
|
||||
else:
|
||||
Foo = 42
|
||||
|
||||
return Foo
|
||||
|
||||
|
||||
# `with` statements
|
||||
def foo():
|
||||
with open("foo.txt", "r") as f:
|
||||
x = f.read()
|
||||
return x # RET504
|
||||
|
||||
|
||||
def foo():
|
||||
with open("foo.txt", "r") as f:
|
||||
x = f.read()
|
||||
print(x)
|
||||
return x
|
||||
|
||||
|
||||
def foo():
|
||||
with open("foo.txt", "r") as f:
|
||||
x = f.read()
|
||||
print(x)
|
||||
return x
|
||||
|
||||
|
||||
# Autofix cases
|
||||
def foo():
|
||||
a = 1
|
||||
b=a
|
||||
return b # RET504
|
||||
|
||||
|
||||
def foo():
|
||||
a = 1
|
||||
b =a
|
||||
return b # RET504
|
||||
|
||||
|
||||
def foo():
|
||||
a = 1
|
||||
b= a
|
||||
return b # RET504
|
||||
|
||||
|
||||
def foo():
|
||||
a = 1 # Comment
|
||||
return a
|
||||
|
||||
@@ -53,6 +53,9 @@ class Foo(metaclass=BazMeta):
|
||||
def __really_private_func(self, arg):
|
||||
super().__really_private_func(arg)
|
||||
|
||||
def __eq__(self, other):
|
||||
return self._private_thing == other._private_thing
|
||||
|
||||
|
||||
foo = Foo()
|
||||
|
||||
|
||||
@@ -171,3 +171,17 @@ def f():
|
||||
if x.isdigit():
|
||||
return True
|
||||
return False
|
||||
|
||||
async def f():
|
||||
# OK
|
||||
for x in iterable:
|
||||
if await check(x):
|
||||
return True
|
||||
return False
|
||||
|
||||
async def f():
|
||||
# SIM110
|
||||
for x in iterable:
|
||||
if check(x):
|
||||
return True
|
||||
return False
|
||||
|
||||
@@ -33,17 +33,17 @@ with A() as a:
|
||||
print("hello")
|
||||
a()
|
||||
|
||||
# OK
|
||||
# OK, can't merge async with and with.
|
||||
async with A() as a:
|
||||
with B() as b:
|
||||
print("hello")
|
||||
|
||||
# OK
|
||||
# OK, can't merge async with and with.
|
||||
with A() as a:
|
||||
async with B() as b:
|
||||
print("hello")
|
||||
|
||||
# OK
|
||||
# SIM117
|
||||
async with A() as a:
|
||||
async with B() as b:
|
||||
print("hello")
|
||||
@@ -99,4 +99,25 @@ with A("01ß9💣2ℝ8901ß9💣2ℝ8901ß9💣2ℝ89") as a:
|
||||
# SIM117 (not auto-fixable too long)
|
||||
with A("01ß9💣2ℝ8901ß9💣2ℝ8901ß9💣2ℝ890") as a:
|
||||
with B("01ß9💣2ℝ8901ß9💣2ℝ8901ß9💣2ℝ89") as b:
|
||||
print("hello")
|
||||
print("hello")
|
||||
|
||||
# From issue #3025.
|
||||
async def main():
|
||||
async with A() as a: # SIM117.
|
||||
async with B() as b:
|
||||
print("async-inside!")
|
||||
|
||||
return 0
|
||||
|
||||
# OK. Can't merge across different kinds of with statements.
|
||||
with a as a2:
|
||||
async with b as b2:
|
||||
with c as c2:
|
||||
async with d as d2:
|
||||
f(a2, b2, c2, d2)
|
||||
|
||||
# OK. Can't merge across different kinds of with statements.
|
||||
async with b as b2:
|
||||
with c as c2:
|
||||
async with d as d2:
|
||||
f(b2, c2, d2)
|
||||
|
||||
6
crates/ruff/resources/test/fixtures/flake8_slots/SLOT000.py
vendored
Normal file
6
crates/ruff/resources/test/fixtures/flake8_slots/SLOT000.py
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
class Bad(str): # SLOT000
|
||||
pass
|
||||
|
||||
|
||||
class Good(str): # Ok
|
||||
__slots__ = ["foo"]
|
||||
21
crates/ruff/resources/test/fixtures/flake8_slots/SLOT001.py
vendored
Normal file
21
crates/ruff/resources/test/fixtures/flake8_slots/SLOT001.py
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
class Bad(tuple): # SLOT001
|
||||
pass
|
||||
|
||||
|
||||
class Good(tuple): # Ok
|
||||
__slots__ = ("foo",)
|
||||
|
||||
|
||||
from typing import Tuple
|
||||
|
||||
|
||||
class Bad(Tuple): # SLOT001
|
||||
pass
|
||||
|
||||
|
||||
class Bad(Tuple[str, int, float]): # SLOT001
|
||||
pass
|
||||
|
||||
|
||||
class Good(Tuple[str, int, float]): # OK
|
||||
__slots__ = ("foo",)
|
||||
14
crates/ruff/resources/test/fixtures/flake8_slots/SLOT002.py
vendored
Normal file
14
crates/ruff/resources/test/fixtures/flake8_slots/SLOT002.py
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
from collections import namedtuple
|
||||
from typing import NamedTuple
|
||||
|
||||
|
||||
class Bad(namedtuple("foo", ["str", "int"])): # SLOT002
|
||||
pass
|
||||
|
||||
|
||||
class Good(namedtuple("foo", ["str", "int"])): # OK
|
||||
__slots__ = ("foo",)
|
||||
|
||||
|
||||
class Good(NamedTuple): # Ok
|
||||
pass
|
||||
@@ -1,6 +1,6 @@
|
||||
# TDO003 - accepted
|
||||
# TODO: this comment has a link
|
||||
# https://github.com/charliermarsh/ruff/issues/3870
|
||||
# https://github.com/astral-sh/ruff/issues/3870
|
||||
|
||||
# TODO: this comment has an issue
|
||||
# TDO-3870
|
||||
|
||||
@@ -164,3 +164,11 @@ def f():
|
||||
)
|
||||
|
||||
x: DataFrame = 2
|
||||
|
||||
|
||||
def f():
|
||||
global Member
|
||||
|
||||
from module import Member
|
||||
|
||||
x: Member = 1
|
||||
|
||||
37
crates/ruff/resources/test/fixtures/jupyter/after_fix.ipynb
vendored
Normal file
37
crates/ruff/resources/test/fixtures/jupyter/after_fix.ipynb
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "1",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import math\n",
|
||||
"\n",
|
||||
"math.pi"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python (ruff)",
|
||||
"language": "python",
|
||||
"name": "ruff"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.11.3"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
38
crates/ruff/resources/test/fixtures/jupyter/before_fix.ipynb
vendored
Normal file
38
crates/ruff/resources/test/fixtures/jupyter/before_fix.ipynb
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "1",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import math\n",
|
||||
"import os\n",
|
||||
"\n",
|
||||
"math.pi"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python (ruff)",
|
||||
"language": "python",
|
||||
"name": "ruff"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.11.3"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
8
crates/ruff/resources/test/fixtures/jupyter/cell/code_and_magic.json
vendored
Normal file
8
crates/ruff/resources/test/fixtures/jupyter/cell/code_and_magic.json
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"execution_count": null,
|
||||
"cell_type": "code",
|
||||
"id": "1",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": ["def foo():\n", " pass\n", "\n", "%timeit foo()"]
|
||||
}
|
||||
6
crates/ruff/resources/test/fixtures/jupyter/cell/markdown.json
vendored
Normal file
6
crates/ruff/resources/test/fixtures/jupyter/cell/markdown.json
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "1",
|
||||
"metadata": {},
|
||||
"source": ["This is a markdown cell\n", "Some more content"]
|
||||
}
|
||||
8
crates/ruff/resources/test/fixtures/jupyter/cell/only_code.json
vendored
Normal file
8
crates/ruff/resources/test/fixtures/jupyter/cell/only_code.json
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"execution_count": null,
|
||||
"cell_type": "code",
|
||||
"id": "1",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": ["def foo():\n", " pass"]
|
||||
}
|
||||
8
crates/ruff/resources/test/fixtures/jupyter/cell/only_magic.json
vendored
Normal file
8
crates/ruff/resources/test/fixtures/jupyter/cell/only_magic.json
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"execution_count": null,
|
||||
"cell_type": "code",
|
||||
"id": "1",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": "%timeit print('hello world')"
|
||||
}
|
||||
51
crates/ruff/resources/test/fixtures/jupyter/isort.ipynb
vendored
Normal file
51
crates/ruff/resources/test/fixtures/jupyter/isort.ipynb
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "0c7535f6-43cb-423f-bfe1-d263b8f55da0",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from pathlib import Path\n",
|
||||
"import random\n",
|
||||
"import math"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "c066fa1a-5682-47af-8c17-5afec3cf4ad0",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from typing import Any\n",
|
||||
"import collections\n",
|
||||
"# Newline should be added here\n",
|
||||
"def foo():\n",
|
||||
" pass"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python (ruff)",
|
||||
"language": "python",
|
||||
"name": "ruff"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.11.3"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
53
crates/ruff/resources/test/fixtures/jupyter/isort_expected.ipynb
vendored
Normal file
53
crates/ruff/resources/test/fixtures/jupyter/isort_expected.ipynb
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "663ba955-baca-4f34-9ebb-840d2573ae3f",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import math\n",
|
||||
"import random\n",
|
||||
"from pathlib import Path"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "d0adfe23-8aea-47e9-bf67-d856cfcb96ea",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import collections\n",
|
||||
"from typing import Any\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"# Newline should be added here\n",
|
||||
"def foo():\n",
|
||||
" pass"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python (ruff)",
|
||||
"language": "python",
|
||||
"name": "ruff"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.11.3"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
@@ -3,6 +3,16 @@
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2023-03-08T23:01:09.782916Z",
|
||||
"start_time": "2023-03-08T23:01:09.705831Z"
|
||||
},
|
||||
"collapsed": false,
|
||||
"jupyter": {
|
||||
"outputs_hidden": false
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
@@ -19,32 +29,26 @@
|
||||
" print(f\"cell one: {y}\")\n",
|
||||
"\n",
|
||||
"unused_variable()"
|
||||
],
|
||||
"metadata": {
|
||||
"collapsed": false,
|
||||
"ExecuteTime": {
|
||||
"start_time": "2023-03-08T23:01:09.705831Z",
|
||||
"end_time": "2023-03-08T23:01:09.782916Z"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Let's do another mistake"
|
||||
],
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"metadata": {
|
||||
"collapsed": true,
|
||||
"ExecuteTime": {
|
||||
"start_time": "2023-03-08T23:01:09.733809Z",
|
||||
"end_time": "2023-03-08T23:01:09.915760Z"
|
||||
"end_time": "2023-03-08T23:01:09.915760Z",
|
||||
"start_time": "2023-03-08T23:01:09.733809Z"
|
||||
},
|
||||
"collapsed": true,
|
||||
"jupyter": {
|
||||
"outputs_hidden": true
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
@@ -62,27 +66,66 @@
|
||||
"\n",
|
||||
"mutable_argument()\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Let's create an empty cell"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Multi-line empty cell!"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"print(\"after empty cells\")"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"display_name": "Python (ruff)",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
"name": "ruff"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 2
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython2",
|
||||
"version": "2.7.6"
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.11.3"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 0
|
||||
"nbformat_minor": 4
|
||||
}
|
||||
|
||||
11
crates/ruff/resources/test/fixtures/pep8_naming/ignore_names/N801.py
vendored
Normal file
11
crates/ruff/resources/test/fixtures/pep8_naming/ignore_names/N801.py
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
class badAllowed:
|
||||
pass
|
||||
|
||||
class stillBad:
|
||||
pass
|
||||
|
||||
class BAD_ALLOWED:
|
||||
pass
|
||||
|
||||
class STILL_BAD:
|
||||
pass
|
||||
14
crates/ruff/resources/test/fixtures/pep8_naming/ignore_names/N802.py
vendored
Normal file
14
crates/ruff/resources/test/fixtures/pep8_naming/ignore_names/N802.py
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
import unittest
|
||||
|
||||
def badAllowed():
|
||||
pass
|
||||
|
||||
def stillBad():
|
||||
pass
|
||||
|
||||
class Test(unittest.TestCase):
|
||||
def badAllowed(self):
|
||||
return super().tearDown()
|
||||
|
||||
def stillBad(self):
|
||||
return super().tearDown()
|
||||
12
crates/ruff/resources/test/fixtures/pep8_naming/ignore_names/N803.py
vendored
Normal file
12
crates/ruff/resources/test/fixtures/pep8_naming/ignore_names/N803.py
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
def func(_, a, badAllowed):
|
||||
return _, a, badAllowed
|
||||
|
||||
def func(_, a, stillBad):
|
||||
return _, a, stillBad
|
||||
|
||||
class Class:
|
||||
def method(self, _, a, badAllowed):
|
||||
return _, a, badAllowed
|
||||
|
||||
def method(self, _, a, stillBad):
|
||||
return _, a, stillBad
|
||||
22
crates/ruff/resources/test/fixtures/pep8_naming/ignore_names/N804.py
vendored
Normal file
22
crates/ruff/resources/test/fixtures/pep8_naming/ignore_names/N804.py
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
from abc import ABCMeta
|
||||
|
||||
|
||||
class Class:
|
||||
def __init_subclass__(self, default_name, **kwargs):
|
||||
...
|
||||
|
||||
@classmethod
|
||||
def badAllowed(self, x, /, other):
|
||||
...
|
||||
|
||||
@classmethod
|
||||
def stillBad(self, x, /, other):
|
||||
...
|
||||
|
||||
|
||||
class MetaClass(ABCMeta):
|
||||
def badAllowed(self):
|
||||
pass
|
||||
|
||||
def stillBad(self):
|
||||
pass
|
||||
42
crates/ruff/resources/test/fixtures/pep8_naming/ignore_names/N805.py
vendored
Normal file
42
crates/ruff/resources/test/fixtures/pep8_naming/ignore_names/N805.py
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
from abc import ABCMeta
|
||||
|
||||
import pydantic
|
||||
|
||||
|
||||
class Class:
|
||||
def badAllowed(this):
|
||||
pass
|
||||
|
||||
def stillBad(this):
|
||||
pass
|
||||
|
||||
if False:
|
||||
|
||||
def badAllowed(this):
|
||||
pass
|
||||
|
||||
def stillBad(this):
|
||||
pass
|
||||
|
||||
@pydantic.validator
|
||||
def badAllowed(cls, my_field: str) -> str:
|
||||
pass
|
||||
|
||||
@pydantic.validator
|
||||
def stillBad(cls, my_field: str) -> str:
|
||||
pass
|
||||
|
||||
@pydantic.validator("my_field")
|
||||
def badAllowed(cls, my_field: str) -> str:
|
||||
pass
|
||||
|
||||
@pydantic.validator("my_field")
|
||||
def stillBad(cls, my_field: str) -> str:
|
||||
pass
|
||||
|
||||
class PosOnlyClass:
|
||||
def badAllowed(this, blah, /, self, something: str):
|
||||
pass
|
||||
|
||||
def stillBad(this, blah, /, self, something: str):
|
||||
pass
|
||||
6
crates/ruff/resources/test/fixtures/pep8_naming/ignore_names/N806.py
vendored
Normal file
6
crates/ruff/resources/test/fixtures/pep8_naming/ignore_names/N806.py
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
def assign():
|
||||
badAllowed = 0
|
||||
stillBad = 0
|
||||
|
||||
BAD_ALLOWED = 0
|
||||
STILL_BAD = 0
|
||||
13
crates/ruff/resources/test/fixtures/pep8_naming/ignore_names/N807.py
vendored
Normal file
13
crates/ruff/resources/test/fixtures/pep8_naming/ignore_names/N807.py
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
def __badAllowed__():
|
||||
pass
|
||||
|
||||
def __stillBad__():
|
||||
pass
|
||||
|
||||
|
||||
def nested():
|
||||
def __badAllowed__():
|
||||
pass
|
||||
|
||||
def __stillBad__():
|
||||
pass
|
||||
5
crates/ruff/resources/test/fixtures/pep8_naming/ignore_names/N811.py
vendored
Normal file
5
crates/ruff/resources/test/fixtures/pep8_naming/ignore_names/N811.py
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
import mod.BAD_ALLOWED as badAllowed
|
||||
import mod.STILL_BAD as stillBad
|
||||
|
||||
from mod import BAD_ALLOWED as badAllowed
|
||||
from mod import STILL_BAD as stillBad
|
||||
5
crates/ruff/resources/test/fixtures/pep8_naming/ignore_names/N812.py
vendored
Normal file
5
crates/ruff/resources/test/fixtures/pep8_naming/ignore_names/N812.py
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
import mod.badallowed as badAllowed
|
||||
import mod.stillbad as stillBad
|
||||
|
||||
from mod import badallowed as BadAllowed
|
||||
from mod import stillbad as StillBad
|
||||
8
crates/ruff/resources/test/fixtures/pep8_naming/ignore_names/N813.py
vendored
Normal file
8
crates/ruff/resources/test/fixtures/pep8_naming/ignore_names/N813.py
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
import mod.BadAllowed as badallowed
|
||||
import mod.stillBad as stillbad
|
||||
|
||||
from mod import BadAllowed as badallowed
|
||||
from mod import StillBad as stillbad
|
||||
|
||||
from mod import BadAllowed as bad_allowed
|
||||
from mod import StillBad as still_bad
|
||||
8
crates/ruff/resources/test/fixtures/pep8_naming/ignore_names/N814.py
vendored
Normal file
8
crates/ruff/resources/test/fixtures/pep8_naming/ignore_names/N814.py
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
import mod.BadAllowed as BADALLOWED
|
||||
import mod.StillBad as STILLBAD
|
||||
|
||||
from mod import BadAllowed as BADALLOWED
|
||||
from mod import StillBad as STILLBAD
|
||||
|
||||
from mod import BadAllowed as BAD_ALLOWED
|
||||
from mod import StillBad as STILL_BAD
|
||||
19
crates/ruff/resources/test/fixtures/pep8_naming/ignore_names/N815.py
vendored
Normal file
19
crates/ruff/resources/test/fixtures/pep8_naming/ignore_names/N815.py
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
class C:
|
||||
badAllowed = 0
|
||||
stillBad = 0
|
||||
|
||||
_badAllowed = 0
|
||||
_stillBad = 0
|
||||
|
||||
bad_Allowed = 0
|
||||
still_Bad = 0
|
||||
|
||||
class D(TypedDict):
|
||||
badAllowed: bool
|
||||
stillBad: bool
|
||||
|
||||
_badAllowed: list
|
||||
_stillBad: list
|
||||
|
||||
bad_Allowed: set
|
||||
still_Bad: set
|
||||
8
crates/ruff/resources/test/fixtures/pep8_naming/ignore_names/N816.py
vendored
Normal file
8
crates/ruff/resources/test/fixtures/pep8_naming/ignore_names/N816.py
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
badAllowed = 0
|
||||
stillBad = 0
|
||||
|
||||
_badAllowed = 0
|
||||
_stillBad = 0
|
||||
|
||||
bad_Allowed = 0
|
||||
still_Bad = 0
|
||||
5
crates/ruff/resources/test/fixtures/pep8_naming/ignore_names/N817.py
vendored
Normal file
5
crates/ruff/resources/test/fixtures/pep8_naming/ignore_names/N817.py
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
import mod.BadAllowed as BA
|
||||
import mod.StillBad as SB
|
||||
|
||||
from mod import BadAllowed as BA
|
||||
from mod import StillBad as SB
|
||||
11
crates/ruff/resources/test/fixtures/pep8_naming/ignore_names/N818.py
vendored
Normal file
11
crates/ruff/resources/test/fixtures/pep8_naming/ignore_names/N818.py
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
class BadAllowed(Exception):
|
||||
pass
|
||||
|
||||
class StillBad(Exception):
|
||||
pass
|
||||
|
||||
class BadAllowed(AnotherError):
|
||||
pass
|
||||
|
||||
class StillBad(AnotherError):
|
||||
pass
|
||||
0
crates/ruff/resources/test/fixtures/pep8_naming/ignore_names/N999/badAllowed/__init__.py
vendored
Normal file
0
crates/ruff/resources/test/fixtures/pep8_naming/ignore_names/N999/badAllowed/__init__.py
vendored
Normal file
71
crates/ruff/resources/test/fixtures/perflint/PERF102.py
vendored
Normal file
71
crates/ruff/resources/test/fixtures/perflint/PERF102.py
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
some_dict = {"a": 12, "b": 32, "c": 44}
|
||||
|
||||
for _, value in some_dict.items(): # PERF102
|
||||
print(value)
|
||||
|
||||
|
||||
for key, _ in some_dict.items(): # PERF102
|
||||
print(key)
|
||||
|
||||
|
||||
for weird_arg_name, _ in some_dict.items(): # PERF102
|
||||
print(weird_arg_name)
|
||||
|
||||
|
||||
for name, (_, _) in some_dict.items(): # PERF102
|
||||
pass
|
||||
|
||||
|
||||
for name, (value1, _) in some_dict.items(): # OK
|
||||
pass
|
||||
|
||||
|
||||
for (key1, _), (_, _) in some_dict.items(): # PERF102
|
||||
pass
|
||||
|
||||
|
||||
for (_, (_, _)), (value, _) in some_dict.items(): # PERF102
|
||||
pass
|
||||
|
||||
|
||||
for (_, key2), (value1, _) in some_dict.items(): # OK
|
||||
pass
|
||||
|
||||
|
||||
for ((_, key2), (value1, _)) in some_dict.items(): # OK
|
||||
pass
|
||||
|
||||
|
||||
for ((_, key2), (_, _)) in some_dict.items(): # PERF102
|
||||
pass
|
||||
|
||||
|
||||
for (_, _, _, variants), (r_language, _, _, _) in some_dict.items(): # OK
|
||||
pass
|
||||
|
||||
|
||||
for (_, _, (_, variants)), (_, (_, (r_language, _))) in some_dict.items(): # OK
|
||||
pass
|
||||
|
||||
|
||||
for key, value in some_dict.items(): # OK
|
||||
print(key, value)
|
||||
|
||||
|
||||
for _, value in some_dict.items(12): # OK
|
||||
print(value)
|
||||
|
||||
|
||||
for key in some_dict.keys(): # OK
|
||||
print(key)
|
||||
|
||||
|
||||
for value in some_dict.values(): # OK
|
||||
print(value)
|
||||
|
||||
|
||||
for name, (_, _) in (some_function()).items(): # PERF102
|
||||
pass
|
||||
|
||||
for name, (_, _) in (some_function().some_attribute).items(): # PERF102
|
||||
pass
|
||||
@@ -60,3 +60,6 @@ match *0, 1, *2:
|
||||
#:
|
||||
class Foo:
|
||||
match: Optional[Match] = None
|
||||
#: E702:2:4
|
||||
while 1:
|
||||
1;...
|
||||
|
||||
32
crates/ruff/resources/test/fixtures/pyflakes/F401_17.py
vendored
Normal file
32
crates/ruff/resources/test/fixtures/pyflakes/F401_17.py
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
"""Test that runtime typing references are properly attributed to scoped imports."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING, cast
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from threading import Thread
|
||||
|
||||
|
||||
def fn(thread: Thread):
|
||||
from threading import Thread
|
||||
|
||||
# The `Thread` on the left-hand side should resolve to the `Thread` imported at the
|
||||
# top level.
|
||||
x: Thread
|
||||
|
||||
|
||||
def fn(thread: Thread):
|
||||
from threading import Thread
|
||||
|
||||
# The `Thread` on the left-hand side should resolve to the `Thread` imported at the
|
||||
# top level.
|
||||
cast("Thread", thread)
|
||||
|
||||
|
||||
def fn(thread: Thread):
|
||||
from threading import Thread
|
||||
|
||||
# The `Thread` on the right-hand side should resolve to the`Thread` imported within
|
||||
# `fn`.
|
||||
cast(Thread, thread)
|
||||
11
crates/ruff/resources/test/fixtures/pyflakes/F401_18.py
vendored
Normal file
11
crates/ruff/resources/test/fixtures/pyflakes/F401_18.py
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
"""Test that straight `__future__` imports are considered unused."""
|
||||
|
||||
|
||||
def f():
|
||||
import __future__
|
||||
|
||||
|
||||
def f():
|
||||
import __future__
|
||||
|
||||
print(__future__.absolute_import)
|
||||
@@ -7,3 +7,5 @@ hidden = {"a": "!"}
|
||||
|
||||
"%(a)s" % {"a": 1, r"b": "!"} # F504 ("b" not used)
|
||||
"%(a)s" % {'a': 1, u"b": "!"} # F504 ("b" not used)
|
||||
|
||||
'' % {'a''b' : ''} # F504 ("ab" not used)
|
||||
|
||||
@@ -19,3 +19,9 @@ if ("123" != x) is 3:
|
||||
|
||||
if "123" != (x is 3):
|
||||
pass
|
||||
|
||||
{2 is
|
||||
not ''}
|
||||
|
||||
{2 is
|
||||
not ''}
|
||||
|
||||
@@ -126,3 +126,22 @@ def f(x: int):
|
||||
def f():
|
||||
if any((key := (value := x)) for x in ["ok"]):
|
||||
print(key)
|
||||
|
||||
|
||||
def f() -> None:
|
||||
is_connected = False
|
||||
|
||||
class Foo:
|
||||
@property
|
||||
def is_connected(self):
|
||||
nonlocal is_connected
|
||||
return is_connected
|
||||
|
||||
def do_thing(self):
|
||||
# This should resolve to the `is_connected` in the function scope.
|
||||
nonlocal is_connected
|
||||
print(is_connected)
|
||||
|
||||
obj = Foo()
|
||||
obj.do_thing()
|
||||
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
from __future__ import annotations
|
||||
|
||||
|
||||
# Test case for https://github.com/charliermarsh/ruff/issues/1552
|
||||
# Test case for https://github.com/astral-sh/ruff/issues/1552
|
||||
def f():
|
||||
x = 0
|
||||
list()[x:]
|
||||
|
||||
|
||||
# Test case for https://github.com/charliermarsh/ruff/issues/2603
|
||||
# Test case for https://github.com/astral-sh/ruff/issues/2603
|
||||
def f():
|
||||
KeyTupleT = tuple[str, ...]
|
||||
|
||||
|
||||
@@ -108,3 +108,42 @@ def f():
|
||||
|
||||
def f():
|
||||
toplevel = tt = 1
|
||||
|
||||
|
||||
def f(provided: int) -> int:
|
||||
match provided:
|
||||
case [_, *x]:
|
||||
pass
|
||||
|
||||
|
||||
def f(provided: int) -> int:
|
||||
match provided:
|
||||
case x:
|
||||
pass
|
||||
|
||||
|
||||
def f(provided: int) -> int:
|
||||
match provided:
|
||||
case Foo(bar) as x:
|
||||
pass
|
||||
|
||||
|
||||
def f(provided: int) -> int:
|
||||
match provided:
|
||||
case {"foo": 0, **x}:
|
||||
pass
|
||||
|
||||
|
||||
def f(provided: int) -> int:
|
||||
match provided:
|
||||
case {**x}:
|
||||
pass
|
||||
|
||||
|
||||
global CONSTANT
|
||||
|
||||
|
||||
def f() -> None:
|
||||
global CONSTANT
|
||||
CONSTANT = 1
|
||||
CONSTANT = 2
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
if True:
|
||||
import foo1; x = 1
|
||||
import foo2; x = 1
|
||||
@@ -11,7 +10,6 @@ if True:
|
||||
import foo4 \
|
||||
; x = 1
|
||||
|
||||
|
||||
if True:
|
||||
x = 1; import foo5
|
||||
|
||||
@@ -20,12 +18,10 @@ if True:
|
||||
x = 1; \
|
||||
import foo6
|
||||
|
||||
|
||||
if True:
|
||||
x = 1 \
|
||||
; import foo7
|
||||
|
||||
|
||||
if True:
|
||||
x = 1; import foo8; x = 1
|
||||
x = 1; import foo9; x = 1
|
||||
@@ -40,12 +36,27 @@ if True:
|
||||
;import foo11 \
|
||||
;x = 1
|
||||
|
||||
if True:
|
||||
x = 1; \
|
||||
\
|
||||
import foo12
|
||||
|
||||
if True:
|
||||
x = 1; \
|
||||
\
|
||||
import foo13
|
||||
|
||||
|
||||
if True:
|
||||
x = 1; \
|
||||
# \
|
||||
import foo14
|
||||
|
||||
# Continuation, but not as the last content in the file.
|
||||
x = 1; \
|
||||
import foo12
|
||||
import foo15
|
||||
|
||||
# Continuation, followed by end-of-file. (Removing `import foo` would cause a syntax
|
||||
# error.)
|
||||
x = 1; \
|
||||
import foo13
|
||||
import foo16
|
||||
45
crates/ruff/resources/test/fixtures/pylint/comparison_with_itself.py
vendored
Normal file
45
crates/ruff/resources/test/fixtures/pylint/comparison_with_itself.py
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
# Errors.
|
||||
foo == foo
|
||||
|
||||
foo != foo
|
||||
|
||||
foo > foo
|
||||
|
||||
foo >= foo
|
||||
|
||||
foo < foo
|
||||
|
||||
foo <= foo
|
||||
|
||||
foo is foo
|
||||
|
||||
foo is not foo
|
||||
|
||||
foo in foo
|
||||
|
||||
foo not in foo
|
||||
|
||||
# Non-errors.
|
||||
"foo" == "foo" # This is flagged by `comparison-of-constant` instead.
|
||||
|
||||
foo == "foo"
|
||||
|
||||
foo == bar
|
||||
|
||||
foo != bar
|
||||
|
||||
foo > bar
|
||||
|
||||
foo >= bar
|
||||
|
||||
foo < bar
|
||||
|
||||
foo <= bar
|
||||
|
||||
foo is bar
|
||||
|
||||
foo is not bar
|
||||
|
||||
foo in bar
|
||||
|
||||
foo not in bar
|
||||
@@ -73,3 +73,10 @@ def override_class():
|
||||
pass
|
||||
|
||||
CLASS()
|
||||
|
||||
|
||||
def multiple_assignment():
|
||||
"""Should warn on every assignment."""
|
||||
global CONSTANT # [global-statement]
|
||||
CONSTANT = 1
|
||||
CONSTANT = 2
|
||||
|
||||
@@ -14,6 +14,12 @@ __all__ = (x for x in ["Hello", "world"]) # [invalid-all-format]
|
||||
|
||||
__all__ = {x for x in ["Hello", "world"]} # [invalid-all-format]
|
||||
|
||||
__all__ = foo # [invalid-all-format]
|
||||
|
||||
__all__ = foo.bar # [invalid-all-format]
|
||||
|
||||
__all__ = foo["bar"] # [invalid-all-format]
|
||||
|
||||
__all__ = ["Hello"]
|
||||
|
||||
__all__ = ("Hello",)
|
||||
@@ -29,3 +35,8 @@ __all__ = list({"Hello", "world"})
|
||||
__all__ = list(["Hello"]) + list(["world"])
|
||||
|
||||
__all__ = tuple(["Hello"]) + ("world",)
|
||||
|
||||
__all__ = __all__ + ["Hello"]
|
||||
|
||||
__all__ = __all__ + multiprocessing.__all__
|
||||
|
||||
|
||||
@@ -3,12 +3,6 @@
|
||||
for item in {"apples", "lemons", "water"}: # flags in-line set literals
|
||||
print(f"I like {item}.")
|
||||
|
||||
for item in set(("apples", "lemons", "water")): # flags set() calls
|
||||
print(f"I like {item}.")
|
||||
|
||||
for number in {i for i in range(10)}: # flags set comprehensions
|
||||
print(number)
|
||||
|
||||
numbers_list = [i for i in {1, 2, 3}] # flags sets in list comprehensions
|
||||
|
||||
numbers_set = {i for i in {1, 2, 3}} # flags sets in set comprehensions
|
||||
@@ -36,3 +30,9 @@ numbers_set = {i for i in (1, 2, 3)} # tuples in comprehensions are fine
|
||||
numbers_dict = {str(i): i for i in [1, 2, 3]} # lists in dict comprehensions are fine
|
||||
|
||||
numbers_gen = (i for i in (1, 2, 3)) # tuples in generator expressions are fine
|
||||
|
||||
for item in set(("apples", "lemons", "water")): # set constructor is fine
|
||||
print(f"I like {item}.")
|
||||
|
||||
for number in {i for i in range(10)}: # set comprehensions are fine
|
||||
print(number)
|
||||
|
||||
@@ -31,6 +31,21 @@ with None as i:
|
||||
with None as j: # ok
|
||||
pass
|
||||
|
||||
# Async with -> with, variable reused
|
||||
async with None as i:
|
||||
with None as i: # error
|
||||
pass
|
||||
|
||||
# Async with -> with, different variable
|
||||
async with None as i:
|
||||
with None as j: # ok
|
||||
pass
|
||||
|
||||
# Async for -> for, variable reused
|
||||
async for i in []:
|
||||
for i in []: # error
|
||||
pass
|
||||
|
||||
# For -> for -> for, doubly nested variable reuse
|
||||
for i in []:
|
||||
for j in []:
|
||||
|
||||
@@ -134,6 +134,19 @@ class A(
|
||||
...
|
||||
|
||||
|
||||
class A(object, object):
|
||||
...
|
||||
|
||||
|
||||
@decorator()
|
||||
class A(object):
|
||||
...
|
||||
|
||||
@decorator() # class A(object):
|
||||
class A(object):
|
||||
...
|
||||
|
||||
|
||||
object = A
|
||||
|
||||
|
||||
|
||||
@@ -21,10 +21,6 @@ x = "foo {0}" \
|
||||
|
||||
"\N{snowman} {0}".format(1)
|
||||
|
||||
'{' '0}'.format(1)
|
||||
|
||||
# These will not change because we are waiting for libcst to fix this issue:
|
||||
# https://github.com/Instagram/LibCST/issues/846
|
||||
print(
|
||||
'foo{0}'
|
||||
'bar{1}'.format(1, 2)
|
||||
@@ -34,3 +30,5 @@ print(
|
||||
'foo{0}' # ohai\n"
|
||||
'bar{1}'.format(1, 2)
|
||||
)
|
||||
|
||||
'{' '0}'.format(1)
|
||||
|
||||
@@ -13,3 +13,5 @@ f"{0}".format(a)
|
||||
f"{0}".format(1)
|
||||
|
||||
print(f"{0}".format(1))
|
||||
|
||||
''.format(1)
|
||||
|
||||
43
crates/ruff/resources/test/fixtures/pyupgrade/UP039.py
vendored
Normal file
43
crates/ruff/resources/test/fixtures/pyupgrade/UP039.py
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
# Errors
|
||||
class A():
|
||||
pass
|
||||
|
||||
|
||||
class A() \
|
||||
:
|
||||
pass
|
||||
|
||||
|
||||
class A \
|
||||
():
|
||||
pass
|
||||
|
||||
|
||||
@decorator()
|
||||
class A():
|
||||
pass
|
||||
|
||||
@decorator
|
||||
class A():
|
||||
pass
|
||||
|
||||
# OK
|
||||
class A:
|
||||
pass
|
||||
|
||||
|
||||
class A(A):
|
||||
pass
|
||||
|
||||
|
||||
class A(metaclass=type):
|
||||
pass
|
||||
|
||||
|
||||
@decorator()
|
||||
class A:
|
||||
pass
|
||||
|
||||
@decorator
|
||||
class A:
|
||||
pass
|
||||
@@ -5,12 +5,11 @@ from typing import ClassVar, Sequence
|
||||
KNOWINGLY_MUTABLE_DEFAULT = []
|
||||
|
||||
|
||||
@dataclass()
|
||||
@dataclass
|
||||
class A:
|
||||
mutable_default: list[int] = []
|
||||
immutable_annotation: typing.Sequence[int] = []
|
||||
without_annotation = []
|
||||
ignored_via_comment: list[int] = [] # noqa: RUF008
|
||||
correct_code: list[int] = KNOWINGLY_MUTABLE_DEFAULT
|
||||
perfectly_fine: list[int] = field(default_factory=list)
|
||||
class_variable: typing.ClassVar[list[int]] = []
|
||||
@@ -21,7 +20,6 @@ class B:
|
||||
mutable_default: list[int] = []
|
||||
immutable_annotation: Sequence[int] = []
|
||||
without_annotation = []
|
||||
ignored_via_comment: list[int] = [] # noqa: RUF008
|
||||
correct_code: list[int] = KNOWINGLY_MUTABLE_DEFAULT
|
||||
perfectly_fine: list[int] = field(default_factory=list)
|
||||
class_variable: ClassVar[list[int]] = []
|
||||
|
||||
@@ -28,3 +28,18 @@ def ascii(arg):
|
||||
|
||||
|
||||
f"{ascii(bla)}" # OK
|
||||
|
||||
(
|
||||
f"Member of tuple mismatches type at index {i}. Expected {of_shape_i}. Got "
|
||||
" intermediary content "
|
||||
f" that flows {repr(obj)} of type {type(obj)}.{additional_message}" # RUF010
|
||||
)
|
||||
|
||||
|
||||
f"{str(bla)}" # RUF010
|
||||
|
||||
f"{str(bla):20}" # RUF010
|
||||
|
||||
f"{bla!s}" # RUF010
|
||||
|
||||
f"{bla!s:20}" # OK
|
||||
|
||||
13
crates/ruff/resources/test/fixtures/ruff/RUF011.py
vendored
Normal file
13
crates/ruff/resources/test/fixtures/ruff/RUF011.py
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
data = ["some", "Data"]
|
||||
|
||||
# Ok
|
||||
{value: value.upper() for value in data}
|
||||
{value.lower(): value.upper() for value in data}
|
||||
{v: v*v for v in range(10)}
|
||||
{(0, "a", v): v*v for v in range(10)} # Tuple with variable
|
||||
|
||||
# Errors
|
||||
{"key": value.upper() for value in data}
|
||||
{True: value.upper() for value in data}
|
||||
{0: value.upper() for value in data}
|
||||
{(1, "a"): value.upper() for value in data} # constant tuple
|
||||
33
crates/ruff/resources/test/fixtures/ruff/RUF012.py
vendored
Normal file
33
crates/ruff/resources/test/fixtures/ruff/RUF012.py
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
import typing
|
||||
from typing import ClassVar, Sequence
|
||||
|
||||
KNOWINGLY_MUTABLE_DEFAULT = []
|
||||
|
||||
|
||||
class A:
|
||||
mutable_default: list[int] = []
|
||||
immutable_annotation: typing.Sequence[int] = []
|
||||
without_annotation = []
|
||||
correct_code: list[int] = KNOWINGLY_MUTABLE_DEFAULT
|
||||
class_variable: typing.ClassVar[list[int]] = []
|
||||
|
||||
|
||||
class B:
|
||||
mutable_default: list[int] = []
|
||||
immutable_annotation: Sequence[int] = []
|
||||
without_annotation = []
|
||||
correct_code: list[int] = KNOWINGLY_MUTABLE_DEFAULT
|
||||
class_variable: ClassVar[list[int]] = []
|
||||
|
||||
|
||||
from dataclasses import dataclass, field
|
||||
|
||||
|
||||
@dataclass
|
||||
class C:
|
||||
mutable_default: list[int] = []
|
||||
immutable_annotation: Sequence[int] = []
|
||||
without_annotation = []
|
||||
correct_code: list[int] = KNOWINGLY_MUTABLE_DEFAULT
|
||||
perfectly_fine: list[int] = field(default_factory=list)
|
||||
class_variable: ClassVar[list[int]] = []
|
||||
187
crates/ruff/resources/test/fixtures/ruff/RUF013_0.py
vendored
Normal file
187
crates/ruff/resources/test/fixtures/ruff/RUF013_0.py
vendored
Normal file
@@ -0,0 +1,187 @@
|
||||
import typing
|
||||
from typing import Annotated, Any, Literal, Optional, Tuple, Union
|
||||
|
||||
|
||||
def f(arg: int):
|
||||
pass
|
||||
|
||||
|
||||
def f(arg=None):
|
||||
pass
|
||||
|
||||
|
||||
def f(arg: Any = None):
|
||||
pass
|
||||
|
||||
|
||||
def f(arg: object = None):
|
||||
pass
|
||||
|
||||
|
||||
def f(arg: int = None): # RUF011
|
||||
pass
|
||||
|
||||
|
||||
def f(arg: str = None): # RUF011
|
||||
pass
|
||||
|
||||
|
||||
def f(arg: typing.List[str] = None): # RUF011
|
||||
pass
|
||||
|
||||
|
||||
def f(arg: Tuple[str] = None): # RUF011
|
||||
pass
|
||||
|
||||
|
||||
# Optional
|
||||
|
||||
|
||||
def f(arg: Optional[int] = None):
|
||||
pass
|
||||
|
||||
|
||||
def f(arg: typing.Optional[int] = None):
|
||||
pass
|
||||
|
||||
|
||||
# Union
|
||||
|
||||
|
||||
def f(arg: Union[None, int] = None):
|
||||
pass
|
||||
|
||||
|
||||
def f(arg: Union[str, None] = None):
|
||||
pass
|
||||
|
||||
|
||||
def f(arg: typing.Union[int, str, None] = None):
|
||||
pass
|
||||
|
||||
|
||||
def f(arg: Union[int, str, Any] = None):
|
||||
pass
|
||||
|
||||
|
||||
def f(arg: Union = None): # RUF011
|
||||
pass
|
||||
|
||||
|
||||
def f(arg: Union[int, str] = None): # RUF011
|
||||
pass
|
||||
|
||||
|
||||
def f(arg: typing.Union[int, str] = None): # RUF011
|
||||
pass
|
||||
|
||||
|
||||
# PEP 604 Union
|
||||
|
||||
|
||||
def f(arg: None | int = None):
|
||||
pass
|
||||
|
||||
|
||||
def f(arg: int | None = None):
|
||||
pass
|
||||
|
||||
|
||||
def f(arg: int | float | str | None = None):
|
||||
pass
|
||||
|
||||
|
||||
def f(arg: int | float = None): # RUF011
|
||||
pass
|
||||
|
||||
|
||||
def f(arg: int | float | str | bytes = None): # RUF011
|
||||
pass
|
||||
|
||||
|
||||
# Literal
|
||||
|
||||
|
||||
def f(arg: None = None):
|
||||
pass
|
||||
|
||||
|
||||
def f(arg: Literal[1, 2, None, 3] = None):
|
||||
pass
|
||||
|
||||
|
||||
def f(arg: Literal[1, "foo"] = None): # RUF011
|
||||
pass
|
||||
|
||||
|
||||
def f(arg: typing.Literal[1, "foo", True] = None): # RUF011
|
||||
pass
|
||||
|
||||
|
||||
# Annotated
|
||||
|
||||
|
||||
def f(arg: Annotated[Optional[int], ...] = None):
|
||||
pass
|
||||
|
||||
|
||||
def f(arg: Annotated[Union[int, None], ...] = None):
|
||||
pass
|
||||
|
||||
|
||||
def f(arg: Annotated[Any, ...] = None):
|
||||
pass
|
||||
|
||||
|
||||
def f(arg: Annotated[int, ...] = None): # RUF011
|
||||
pass
|
||||
|
||||
|
||||
def f(arg: Annotated[Annotated[int | str, ...], ...] = None): # RUF011
|
||||
pass
|
||||
|
||||
|
||||
# Multiple arguments
|
||||
|
||||
|
||||
def f(
|
||||
arg1: Optional[int] = None,
|
||||
arg2: Union[int, None] = None,
|
||||
arg3: Literal[1, 2, None, 3] = None,
|
||||
):
|
||||
pass
|
||||
|
||||
|
||||
def f(
|
||||
arg1: int = None, # RUF011
|
||||
arg2: Union[int, float] = None, # RUF011
|
||||
arg3: Literal[1, 2, 3] = None, # RUF011
|
||||
):
|
||||
pass
|
||||
|
||||
|
||||
# Nested
|
||||
|
||||
|
||||
def f(arg: Literal[1, "foo", Literal[True, None]] = None):
|
||||
pass
|
||||
|
||||
|
||||
def f(arg: Union[int, Union[float, Union[str, None]]] = None):
|
||||
pass
|
||||
|
||||
|
||||
def f(arg: Union[int, Union[float, Optional[str]]] = None):
|
||||
pass
|
||||
|
||||
|
||||
def f(arg: Union[int, Literal[True, None]] = None):
|
||||
pass
|
||||
|
||||
|
||||
def f(arg: Union[Annotated[int, ...], Annotated[Optional[float], ...]] = None):
|
||||
pass
|
||||
|
||||
|
||||
def f(arg: Union[Annotated[int, ...], Union[str, bytes]] = None): # RUF011
|
||||
pass
|
||||
5
crates/ruff/resources/test/fixtures/ruff/RUF013_1.py
vendored
Normal file
5
crates/ruff/resources/test/fixtures/ruff/RUF013_1.py
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
# No `typing.Optional` import
|
||||
|
||||
|
||||
def f(arg: int = None): # RUF011
|
||||
pass
|
||||
@@ -1,13 +1,13 @@
|
||||
//! Interface for generating autofix edits from higher-level actions (e.g., "remove an argument").
|
||||
use anyhow::{bail, Result};
|
||||
use ruff_text_size::{TextLen, TextRange, TextSize};
|
||||
use rustpython_parser::ast::{self, Excepthandler, Expr, Keyword, Ranged, Stmt};
|
||||
use rustpython_parser::ast::{self, ExceptHandler, Expr, Keyword, Ranged, Stmt};
|
||||
use rustpython_parser::{lexer, Mode, Tok};
|
||||
|
||||
use ruff_diagnostics::Edit;
|
||||
use ruff_newlines::NewlineWithTrailingNewline;
|
||||
use ruff_python_ast::helpers;
|
||||
use ruff_python_ast::source_code::{Indexer, Locator, Stylist};
|
||||
use ruff_python_whitespace::{is_python_whitespace, NewlineWithTrailingNewline, PythonWhitespace};
|
||||
|
||||
use crate::autofix::codemods;
|
||||
|
||||
@@ -29,7 +29,6 @@ pub(crate) fn delete_stmt(
|
||||
parent: Option<&Stmt>,
|
||||
locator: &Locator,
|
||||
indexer: &Indexer,
|
||||
stylist: &Stylist,
|
||||
) -> Edit {
|
||||
if parent
|
||||
.map(|parent| is_lone_child(stmt, parent))
|
||||
@@ -39,18 +38,15 @@ pub(crate) fn delete_stmt(
|
||||
// it with a `pass`.
|
||||
Edit::range_replacement("pass".to_string(), stmt.range())
|
||||
} else {
|
||||
if let Some(semicolon) = trailing_semicolon(stmt, locator) {
|
||||
if let Some(semicolon) = trailing_semicolon(stmt.end(), locator) {
|
||||
let next = next_stmt_break(semicolon, locator);
|
||||
Edit::deletion(stmt.start(), next)
|
||||
} else if helpers::has_leading_content(stmt, locator) {
|
||||
} else if helpers::has_leading_content(stmt.start(), locator) {
|
||||
Edit::range_deletion(stmt.range())
|
||||
} else if helpers::preceded_by_continuation(stmt, indexer, locator) {
|
||||
if is_end_of_file(stmt, locator) && locator.is_at_start_of_line(stmt.start()) {
|
||||
// Special-case: a file can't end in a continuation.
|
||||
Edit::range_replacement(stylist.line_ending().to_string(), stmt.range())
|
||||
} else {
|
||||
Edit::range_deletion(stmt.range())
|
||||
}
|
||||
} else if let Some(start) =
|
||||
helpers::preceded_by_continuations(stmt.start(), locator, indexer)
|
||||
{
|
||||
Edit::range_deletion(TextRange::new(start, stmt.end()))
|
||||
} else {
|
||||
let range = locator.full_lines_range(stmt.range());
|
||||
Edit::range_deletion(range)
|
||||
@@ -68,7 +64,7 @@ pub(crate) fn remove_unused_imports<'a>(
|
||||
stylist: &Stylist,
|
||||
) -> Result<Edit> {
|
||||
match codemods::remove_imports(unused_imports, stmt, locator, stylist)? {
|
||||
None => Ok(delete_stmt(stmt, parent, locator, indexer, stylist)),
|
||||
None => Ok(delete_stmt(stmt, parent, locator, indexer)),
|
||||
Some(content) => Ok(Edit::range_replacement(content, stmt.range())),
|
||||
}
|
||||
}
|
||||
@@ -218,7 +214,7 @@ fn is_lone_child(child: &Stmt, parent: &Stmt) -> bool {
|
||||
|| is_only(orelse, child)
|
||||
|| is_only(finalbody, child)
|
||||
|| handlers.iter().any(|handler| match handler {
|
||||
Excepthandler::ExceptHandler(ast::ExcepthandlerExceptHandler {
|
||||
ExceptHandler::ExceptHandler(ast::ExceptHandlerExceptHandler {
|
||||
body, ..
|
||||
}) => is_only(body, child),
|
||||
})
|
||||
@@ -238,15 +234,15 @@ fn is_lone_child(child: &Stmt, parent: &Stmt) -> bool {
|
||||
|
||||
/// Return the location of a trailing semicolon following a `Stmt`, if it's part
|
||||
/// of a multi-statement line.
|
||||
fn trailing_semicolon(stmt: &Stmt, locator: &Locator) -> Option<TextSize> {
|
||||
let contents = locator.after(stmt.end());
|
||||
fn trailing_semicolon(offset: TextSize, locator: &Locator) -> Option<TextSize> {
|
||||
let contents = locator.after(offset);
|
||||
|
||||
for line in NewlineWithTrailingNewline::from(contents) {
|
||||
let trimmed = line.trim_start();
|
||||
let trimmed = line.trim_whitespace_start();
|
||||
|
||||
if trimmed.starts_with(';') {
|
||||
let colon_offset = line.text_len() - trimmed.text_len();
|
||||
return Some(stmt.end() + line.start() + colon_offset);
|
||||
return Some(offset + line.start() + colon_offset);
|
||||
}
|
||||
|
||||
if !trimmed.starts_with('\\') {
|
||||
@@ -262,7 +258,7 @@ fn next_stmt_break(semicolon: TextSize, locator: &Locator) -> TextSize {
|
||||
|
||||
let contents = &locator.contents()[usize::from(start_location)..];
|
||||
for line in NewlineWithTrailingNewline::from(contents) {
|
||||
let trimmed = line.trim();
|
||||
let trimmed = line.trim_whitespace();
|
||||
// Skip past any continuations.
|
||||
if trimmed.starts_with('\\') {
|
||||
continue;
|
||||
@@ -276,7 +272,7 @@ fn next_stmt_break(semicolon: TextSize, locator: &Locator) -> TextSize {
|
||||
} else {
|
||||
// Otherwise, find the start of the next statement. (Or, anything that isn't
|
||||
// whitespace.)
|
||||
let relative_offset = line.find(|c: char| !c.is_whitespace()).unwrap();
|
||||
let relative_offset = line.find(|c: char| !is_python_whitespace(c)).unwrap();
|
||||
line.start() + TextSize::try_from(relative_offset).unwrap()
|
||||
};
|
||||
}
|
||||
@@ -284,16 +280,11 @@ fn next_stmt_break(semicolon: TextSize, locator: &Locator) -> TextSize {
|
||||
locator.line_end(start_location)
|
||||
}
|
||||
|
||||
/// Return `true` if a `Stmt` occurs at the end of a file.
|
||||
fn is_end_of_file(stmt: &Stmt, locator: &Locator) -> bool {
|
||||
stmt.end() == locator.contents().text_len()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use anyhow::Result;
|
||||
use ruff_text_size::TextSize;
|
||||
use rustpython_parser::ast::Suite;
|
||||
use rustpython_parser::ast::{Ranged, Suite};
|
||||
use rustpython_parser::Parse;
|
||||
|
||||
use ruff_python_ast::source_code::Locator;
|
||||
@@ -306,19 +297,25 @@ mod tests {
|
||||
let program = Suite::parse(contents, "<filename>")?;
|
||||
let stmt = program.first().unwrap();
|
||||
let locator = Locator::new(contents);
|
||||
assert_eq!(trailing_semicolon(stmt, &locator), None);
|
||||
assert_eq!(trailing_semicolon(stmt.end(), &locator), None);
|
||||
|
||||
let contents = "x = 1; y = 1";
|
||||
let program = Suite::parse(contents, "<filename>")?;
|
||||
let stmt = program.first().unwrap();
|
||||
let locator = Locator::new(contents);
|
||||
assert_eq!(trailing_semicolon(stmt, &locator), Some(TextSize::from(5)));
|
||||
assert_eq!(
|
||||
trailing_semicolon(stmt.end(), &locator),
|
||||
Some(TextSize::from(5))
|
||||
);
|
||||
|
||||
let contents = "x = 1 ; y = 1";
|
||||
let program = Suite::parse(contents, "<filename>")?;
|
||||
let stmt = program.first().unwrap();
|
||||
let locator = Locator::new(contents);
|
||||
assert_eq!(trailing_semicolon(stmt, &locator), Some(TextSize::from(6)));
|
||||
assert_eq!(
|
||||
trailing_semicolon(stmt.end(), &locator),
|
||||
Some(TextSize::from(6))
|
||||
);
|
||||
|
||||
let contents = r#"
|
||||
x = 1 \
|
||||
@@ -328,7 +325,10 @@ x = 1 \
|
||||
let program = Suite::parse(contents, "<filename>")?;
|
||||
let stmt = program.first().unwrap();
|
||||
let locator = Locator::new(contents);
|
||||
assert_eq!(trailing_semicolon(stmt, &locator), Some(TextSize::from(10)));
|
||||
assert_eq!(
|
||||
trailing_semicolon(stmt.end(), &locator),
|
||||
Some(TextSize::from(10))
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -2,23 +2,31 @@ use std::collections::BTreeSet;
|
||||
|
||||
use itertools::Itertools;
|
||||
use nohash_hasher::IntSet;
|
||||
use ruff_text_size::{TextRange, TextSize};
|
||||
use ruff_text_size::{TextLen, TextRange, TextSize};
|
||||
use rustc_hash::FxHashMap;
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Edit, Fix, IsolationLevel};
|
||||
use ruff_python_ast::source_code::Locator;
|
||||
|
||||
use crate::autofix::source_map::SourceMap;
|
||||
use crate::linter::FixTable;
|
||||
use crate::registry::{AsRule, Rule};
|
||||
|
||||
pub(crate) mod codemods;
|
||||
pub(crate) mod edits;
|
||||
pub(crate) mod source_map;
|
||||
|
||||
pub(crate) struct FixResult {
|
||||
/// The resulting source code, after applying all fixes.
|
||||
pub(crate) code: String,
|
||||
/// The number of fixes applied for each [`Rule`].
|
||||
pub(crate) fixes: FixTable,
|
||||
/// Source map for the fixed source code.
|
||||
pub(crate) source_map: SourceMap,
|
||||
}
|
||||
|
||||
/// Auto-fix errors in a file, and write the fixed source code to disk.
|
||||
pub(crate) fn fix_file(
|
||||
diagnostics: &[Diagnostic],
|
||||
locator: &Locator,
|
||||
) -> Option<(String, FixTable)> {
|
||||
pub(crate) fn fix_file(diagnostics: &[Diagnostic], locator: &Locator) -> Option<FixResult> {
|
||||
let mut with_fixes = diagnostics
|
||||
.iter()
|
||||
.filter(|diag| diag.fix.is_some())
|
||||
@@ -35,12 +43,13 @@ pub(crate) fn fix_file(
|
||||
fn apply_fixes<'a>(
|
||||
diagnostics: impl Iterator<Item = &'a Diagnostic>,
|
||||
locator: &'a Locator<'a>,
|
||||
) -> (String, FixTable) {
|
||||
) -> FixResult {
|
||||
let mut output = String::with_capacity(locator.len());
|
||||
let mut last_pos: Option<TextSize> = None;
|
||||
let mut applied: BTreeSet<&Edit> = BTreeSet::default();
|
||||
let mut isolated: IntSet<u32> = IntSet::default();
|
||||
let mut fixed = FxHashMap::default();
|
||||
let mut source_map = SourceMap::default();
|
||||
|
||||
for (rule, fix) in diagnostics
|
||||
.filter_map(|diagnostic| {
|
||||
@@ -84,9 +93,15 @@ fn apply_fixes<'a>(
|
||||
let slice = locator.slice(TextRange::new(last_pos.unwrap_or_default(), edit.start()));
|
||||
output.push_str(slice);
|
||||
|
||||
// Add the start source marker for the patch.
|
||||
source_map.push_start_marker(edit, output.text_len());
|
||||
|
||||
// Add the patch itself.
|
||||
output.push_str(edit.content().unwrap_or_default());
|
||||
|
||||
// Add the end source marker for the added patch.
|
||||
source_map.push_end_marker(edit, output.text_len());
|
||||
|
||||
// Track that the edit was applied.
|
||||
last_pos = Some(edit.end());
|
||||
applied.insert(edit);
|
||||
@@ -99,7 +114,11 @@ fn apply_fixes<'a>(
|
||||
let slice = locator.after(last_pos.unwrap_or_default());
|
||||
output.push_str(slice);
|
||||
|
||||
(output, fixed)
|
||||
FixResult {
|
||||
code: output,
|
||||
fixes: fixed,
|
||||
source_map,
|
||||
}
|
||||
}
|
||||
|
||||
/// Compare two fixes.
|
||||
@@ -110,6 +129,13 @@ fn cmp_fix(rule1: Rule, rule2: Rule, fix1: &Fix, fix2: &Fix) -> std::cmp::Orderi
|
||||
// Apply `EndsInPeriod` fixes before `NewLineAfterLastParagraph` fixes.
|
||||
(Rule::EndsInPeriod, Rule::NewLineAfterLastParagraph) => std::cmp::Ordering::Less,
|
||||
(Rule::NewLineAfterLastParagraph, Rule::EndsInPeriod) => std::cmp::Ordering::Greater,
|
||||
// Apply `IfElseBlockInsteadOfDictGet` fixes before `IfElseBlockInsteadOfIfExp` fixes.
|
||||
(Rule::IfElseBlockInsteadOfDictGet, Rule::IfElseBlockInsteadOfIfExp) => {
|
||||
std::cmp::Ordering::Less
|
||||
}
|
||||
(Rule::IfElseBlockInsteadOfIfExp, Rule::IfElseBlockInsteadOfDictGet) => {
|
||||
std::cmp::Ordering::Greater
|
||||
}
|
||||
_ => std::cmp::Ordering::Equal,
|
||||
})
|
||||
}
|
||||
@@ -123,7 +149,8 @@ mod tests {
|
||||
use ruff_diagnostics::Fix;
|
||||
use ruff_python_ast::source_code::Locator;
|
||||
|
||||
use crate::autofix::apply_fixes;
|
||||
use crate::autofix::source_map::SourceMarker;
|
||||
use crate::autofix::{apply_fixes, FixResult};
|
||||
use crate::rules::pycodestyle::rules::MissingNewlineAtEndOfFile;
|
||||
|
||||
#[allow(deprecated)]
|
||||
@@ -143,9 +170,59 @@ mod tests {
|
||||
fn empty_file() {
|
||||
let locator = Locator::new(r#""#);
|
||||
let diagnostics = create_diagnostics([]);
|
||||
let (contents, fixed) = apply_fixes(diagnostics.iter(), &locator);
|
||||
assert_eq!(contents, "");
|
||||
assert_eq!(fixed.values().sum::<usize>(), 0);
|
||||
let FixResult {
|
||||
code,
|
||||
fixes,
|
||||
source_map,
|
||||
} = apply_fixes(diagnostics.iter(), &locator);
|
||||
assert_eq!(code, "");
|
||||
assert_eq!(fixes.values().sum::<usize>(), 0);
|
||||
assert!(source_map.markers().is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn apply_one_insertion() {
|
||||
let locator = Locator::new(
|
||||
r#"
|
||||
import os
|
||||
|
||||
print("hello world")
|
||||
"#
|
||||
.trim(),
|
||||
);
|
||||
let diagnostics = create_diagnostics([Edit::insertion(
|
||||
"import sys\n".to_string(),
|
||||
TextSize::new(10),
|
||||
)]);
|
||||
let FixResult {
|
||||
code,
|
||||
fixes,
|
||||
source_map,
|
||||
} = apply_fixes(diagnostics.iter(), &locator);
|
||||
assert_eq!(
|
||||
code,
|
||||
r#"
|
||||
import os
|
||||
import sys
|
||||
|
||||
print("hello world")
|
||||
"#
|
||||
.trim()
|
||||
);
|
||||
assert_eq!(fixes.values().sum::<usize>(), 1);
|
||||
assert_eq!(
|
||||
source_map.markers(),
|
||||
&[
|
||||
SourceMarker {
|
||||
source: 10.into(),
|
||||
dest: 10.into(),
|
||||
},
|
||||
SourceMarker {
|
||||
source: 10.into(),
|
||||
dest: 21.into(),
|
||||
},
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -162,16 +239,33 @@ class A(object):
|
||||
TextSize::new(8),
|
||||
TextSize::new(14),
|
||||
)]);
|
||||
let (contents, fixed) = apply_fixes(diagnostics.iter(), &locator);
|
||||
let FixResult {
|
||||
code,
|
||||
fixes,
|
||||
source_map,
|
||||
} = apply_fixes(diagnostics.iter(), &locator);
|
||||
assert_eq!(
|
||||
contents,
|
||||
code,
|
||||
r#"
|
||||
class A(Bar):
|
||||
...
|
||||
"#
|
||||
.trim(),
|
||||
);
|
||||
assert_eq!(fixed.values().sum::<usize>(), 1);
|
||||
assert_eq!(fixes.values().sum::<usize>(), 1);
|
||||
assert_eq!(
|
||||
source_map.markers(),
|
||||
&[
|
||||
SourceMarker {
|
||||
source: 8.into(),
|
||||
dest: 8.into(),
|
||||
},
|
||||
SourceMarker {
|
||||
source: 14.into(),
|
||||
dest: 11.into(),
|
||||
},
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -184,16 +278,33 @@ class A(object):
|
||||
.trim(),
|
||||
);
|
||||
let diagnostics = create_diagnostics([Edit::deletion(TextSize::new(7), TextSize::new(15))]);
|
||||
let (contents, fixed) = apply_fixes(diagnostics.iter(), &locator);
|
||||
let FixResult {
|
||||
code,
|
||||
fixes,
|
||||
source_map,
|
||||
} = apply_fixes(diagnostics.iter(), &locator);
|
||||
assert_eq!(
|
||||
contents,
|
||||
code,
|
||||
r#"
|
||||
class A:
|
||||
...
|
||||
"#
|
||||
.trim()
|
||||
);
|
||||
assert_eq!(fixed.values().sum::<usize>(), 1);
|
||||
assert_eq!(fixes.values().sum::<usize>(), 1);
|
||||
assert_eq!(
|
||||
source_map.markers(),
|
||||
&[
|
||||
SourceMarker {
|
||||
source: 7.into(),
|
||||
dest: 7.into()
|
||||
},
|
||||
SourceMarker {
|
||||
source: 15.into(),
|
||||
dest: 7.into()
|
||||
}
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -209,17 +320,42 @@ class A(object, object, object):
|
||||
Edit::deletion(TextSize::from(8), TextSize::from(16)),
|
||||
Edit::deletion(TextSize::from(22), TextSize::from(30)),
|
||||
]);
|
||||
let (contents, fixed) = apply_fixes(diagnostics.iter(), &locator);
|
||||
let FixResult {
|
||||
code,
|
||||
fixes,
|
||||
source_map,
|
||||
} = apply_fixes(diagnostics.iter(), &locator);
|
||||
|
||||
assert_eq!(
|
||||
contents,
|
||||
code,
|
||||
r#"
|
||||
class A(object):
|
||||
...
|
||||
"#
|
||||
.trim()
|
||||
);
|
||||
assert_eq!(fixed.values().sum::<usize>(), 2);
|
||||
assert_eq!(fixes.values().sum::<usize>(), 2);
|
||||
assert_eq!(
|
||||
source_map.markers(),
|
||||
&[
|
||||
SourceMarker {
|
||||
source: 8.into(),
|
||||
dest: 8.into()
|
||||
},
|
||||
SourceMarker {
|
||||
source: 16.into(),
|
||||
dest: 8.into()
|
||||
},
|
||||
SourceMarker {
|
||||
source: 22.into(),
|
||||
dest: 14.into(),
|
||||
},
|
||||
SourceMarker {
|
||||
source: 30.into(),
|
||||
dest: 14.into(),
|
||||
}
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -235,15 +371,32 @@ class A(object):
|
||||
Edit::deletion(TextSize::from(7), TextSize::from(15)),
|
||||
Edit::replacement("ignored".to_string(), TextSize::from(9), TextSize::from(11)),
|
||||
]);
|
||||
let (contents, fixed) = apply_fixes(diagnostics.iter(), &locator);
|
||||
let FixResult {
|
||||
code,
|
||||
fixes,
|
||||
source_map,
|
||||
} = apply_fixes(diagnostics.iter(), &locator);
|
||||
assert_eq!(
|
||||
contents,
|
||||
code,
|
||||
r#"
|
||||
class A:
|
||||
...
|
||||
"#
|
||||
.trim(),
|
||||
);
|
||||
assert_eq!(fixed.values().sum::<usize>(), 1);
|
||||
assert_eq!(fixes.values().sum::<usize>(), 1);
|
||||
assert_eq!(
|
||||
source_map.markers(),
|
||||
&[
|
||||
SourceMarker {
|
||||
source: 7.into(),
|
||||
dest: 7.into(),
|
||||
},
|
||||
SourceMarker {
|
||||
source: 15.into(),
|
||||
dest: 7.into(),
|
||||
}
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
59
crates/ruff/src/autofix/source_map.rs
Normal file
59
crates/ruff/src/autofix/source_map.rs
Normal file
@@ -0,0 +1,59 @@
|
||||
use ruff_text_size::TextSize;
|
||||
|
||||
use ruff_diagnostics::Edit;
|
||||
|
||||
/// Lightweight sourcemap marker representing the source and destination
|
||||
/// position for an [`Edit`].
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub(crate) struct SourceMarker {
|
||||
/// Position of the marker in the original source.
|
||||
pub(crate) source: TextSize,
|
||||
/// Position of the marker in the transformed code.
|
||||
pub(crate) dest: TextSize,
|
||||
}
|
||||
|
||||
/// A collection of [`SourceMarker`].
|
||||
///
|
||||
/// Sourcemaps are used to map positions in the original source to positions in
|
||||
/// the transformed code. Here, only the boundaries of edits are tracked instead
|
||||
/// of every single character.
|
||||
#[derive(Default, PartialEq, Eq)]
|
||||
pub(crate) struct SourceMap(Vec<SourceMarker>);
|
||||
|
||||
impl SourceMap {
|
||||
/// Returns a slice of all the markers in the sourcemap in the order they
|
||||
/// were added.
|
||||
pub(crate) fn markers(&self) -> &[SourceMarker] {
|
||||
&self.0
|
||||
}
|
||||
|
||||
/// Push the start marker for an [`Edit`].
|
||||
///
|
||||
/// The `output_length` is the length of the transformed string before the
|
||||
/// edit is applied.
|
||||
pub(crate) fn push_start_marker(&mut self, edit: &Edit, output_length: TextSize) {
|
||||
self.0.push(SourceMarker {
|
||||
source: edit.start(),
|
||||
dest: output_length,
|
||||
});
|
||||
}
|
||||
|
||||
/// Push the end marker for an [`Edit`].
|
||||
///
|
||||
/// The `output_length` is the length of the transformed string after the
|
||||
/// edit has been applied.
|
||||
pub(crate) fn push_end_marker(&mut self, edit: &Edit, output_length: TextSize) {
|
||||
if edit.is_insertion() {
|
||||
self.0.push(SourceMarker {
|
||||
source: edit.start(),
|
||||
dest: output_length,
|
||||
});
|
||||
} else {
|
||||
// Deletion or replacement
|
||||
self.0.push(SourceMarker {
|
||||
source: edit.end(),
|
||||
dest: output_length,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,14 @@
|
||||
use ruff_text_size::TextRange;
|
||||
use rustpython_parser::ast::Expr;
|
||||
|
||||
use ruff_python_semantic::model::Snapshot;
|
||||
use ruff_python_semantic::{ScopeId, Snapshot};
|
||||
|
||||
/// A collection of AST nodes that are deferred for later analysis.
|
||||
/// Used to, e.g., store functions, whose bodies shouldn't be analyzed until all
|
||||
/// module-level definitions have been analyzed.
|
||||
#[derive(Debug, Default)]
|
||||
pub(crate) struct Deferred<'a> {
|
||||
pub(crate) scopes: Vec<ScopeId>,
|
||||
pub(crate) string_type_definitions: Vec<(TextRange, &'a str, Snapshot)>,
|
||||
pub(crate) future_type_definitions: Vec<(&'a Expr, Snapshot)>,
|
||||
pub(crate) functions: Vec<Snapshot>,
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user