Compare commits

..

1 Commits

Author SHA1 Message Date
Charlie Marsh
5120b36b67 Consider alternate split points for line-too-long exemptions 2023-11-30 22:53:50 -05:00
553 changed files with 10332 additions and 41173 deletions

View File

@@ -5,10 +5,6 @@ updates:
schedule:
interval: "weekly"
labels: ["internal"]
groups:
actions:
patterns:
- "*"
- package-ecosystem: "cargo"
directory: "/"

View File

@@ -48,8 +48,8 @@ jobs:
- "!crates/ruff_dev/**"
- "!crates/ruff_shrinking/**"
- scripts/*
- python/**
- .github/workflows/ci.yaml
- python/**
formatter:
- Cargo.toml
@@ -68,7 +68,7 @@ jobs:
- .github/workflows/ci.yaml
code:
- "**/*"
- "*/**"
- "!**/*.md"
- "!docs/**"
- "!assets/**"
@@ -86,7 +86,7 @@ jobs:
name: "cargo clippy"
runs-on: ubuntu-latest
needs: determine_changes
if: ${{ needs.determine_changes.outputs.code == 'true' || github.ref == 'refs/heads/main' }}
if: needs.determine_changes.outputs.code == 'true' || github.ref == 'refs/heads/main'
steps:
- uses: actions/checkout@v4
- name: "Install Rust toolchain"
@@ -95,14 +95,14 @@ jobs:
rustup target add wasm32-unknown-unknown
- uses: Swatinem/rust-cache@v2
- name: "Clippy"
run: cargo clippy --workspace --all-targets --all-features --locked -- -D warnings
run: cargo clippy --workspace --all-targets --all-features -- -D warnings
- name: "Clippy (wasm)"
run: cargo clippy -p ruff_wasm --target wasm32-unknown-unknown --all-features --locked -- -D warnings
run: cargo clippy -p ruff_wasm --target wasm32-unknown-unknown --all-features -- -D warnings
cargo-test-linux:
runs-on: ubuntu-latest
needs: determine_changes
if: ${{ needs.determine_changes.outputs.code == 'true' || github.ref == 'refs/heads/main' }}
if: needs.determine_changes.outputs.code == 'true' || github.ref == 'refs/heads/main'
name: "cargo test (linux)"
steps:
- uses: actions/checkout@v4
@@ -128,7 +128,7 @@ jobs:
cargo-test-windows:
runs-on: windows-latest
needs: determine_changes
if: ${{ needs.determine_changes.outputs.code == 'true' || github.ref == 'refs/heads/main' }}
if: needs.determine_changes.outputs.code == 'true' || github.ref == 'refs/heads/main'
name: "cargo test (windows)"
steps:
- uses: actions/checkout@v4
@@ -147,7 +147,7 @@ jobs:
cargo-test-wasm:
runs-on: ubuntu-latest
needs: determine_changes
if: ${{ needs.determine_changes.outputs.code == 'true' || github.ref == 'refs/heads/main' }}
if: needs.determine_changes.outputs.code == 'true' || github.ref == 'refs/heads/main'
name: "cargo test (wasm)"
steps:
- uses: actions/checkout@v4
@@ -168,7 +168,7 @@ jobs:
cargo-fuzz:
runs-on: ubuntu-latest
needs: determine_changes
if: ${{ needs.determine_changes.outputs.code == 'true' || github.ref == 'refs/heads/main' }}
if: needs.determine_changes.outputs.code == 'true' || github.ref == 'refs/heads/main'
name: "cargo fuzz"
steps:
- uses: actions/checkout@v4
@@ -187,7 +187,7 @@ jobs:
name: "test scripts"
runs-on: ubuntu-latest
needs: determine_changes
if: ${{ needs.determine_changes.outputs.code == 'true' || github.ref == 'refs/heads/main' }}
if: needs.determine_changes.outputs.code == 'true' || github.ref == 'refs/heads/main'
steps:
- uses: actions/checkout@v4
- name: "Install Rust toolchain"
@@ -215,7 +215,7 @@ jobs:
}}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
- uses: actions/setup-python@v4
with:
python-version: ${{ env.PYTHON_VERSION }}
@@ -226,7 +226,7 @@ jobs:
name: ruff
path: target/debug
- uses: dawidd6/action-download-artifact@v3
- uses: dawidd6/action-download-artifact@v2
name: Download baseline Ruff binary
with:
name: ruff
@@ -321,7 +321,7 @@ jobs:
name: "cargo udeps"
runs-on: ubuntu-latest
needs: determine_changes
if: ${{ needs.determine_changes.outputs.code == 'true' || github.ref == 'refs/heads/main' }}
if: needs.determine_changes.outputs.code == 'true' || github.ref == 'refs/heads/main'
steps:
- uses: actions/checkout@v4
- name: "Install nightly Rust toolchain"
@@ -338,7 +338,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
- uses: actions/setup-python@v4
with:
python-version: ${{ env.PYTHON_VERSION }}
architecture: x64
@@ -362,7 +362,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
- uses: actions/setup-python@v4
with:
python-version: ${{ env.PYTHON_VERSION }}
- name: "Install Rust toolchain"
@@ -392,7 +392,7 @@ jobs:
MKDOCS_INSIDERS_SSH_KEY_EXISTS: ${{ secrets.MKDOCS_INSIDERS_SSH_KEY != '' }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
- uses: actions/setup-python@v4
- name: "Add SSH key"
if: ${{ env.MKDOCS_INSIDERS_SSH_KEY_EXISTS == 'true' }}
uses: webfactory/ssh-agent@v0.8.0
@@ -444,7 +444,7 @@ jobs:
needs:
- cargo-test-linux
- determine_changes
if: ${{ needs.determine_changes.outputs.code == 'true' || github.ref == 'refs/heads/main' }}
if: needs.determine_changes.outputs.code == 'true' || github.ref == 'refs/heads/main'
steps:
- uses: extractions/setup-just@v1
env:
@@ -455,7 +455,7 @@ jobs:
with:
repository: "astral-sh/ruff-lsp"
- uses: actions/setup-python@v5
- uses: actions/setup-python@v4
with:
python-version: ${{ env.PYTHON_VERSION }}
@@ -483,7 +483,7 @@ jobs:
benchmarks:
runs-on: ubuntu-latest
needs: determine_changes
if: ${{ needs.determine_changes.outputs.code == 'true' || github.ref == 'refs/heads/main' }}
if: needs.determine_changes.outputs.code == 'true' || github.ref == 'refs/heads/main'
steps:
- name: "Checkout Branch"
uses: actions/checkout@v4
@@ -502,7 +502,7 @@ jobs:
run: cargo codspeed build --features codspeed -p ruff_benchmark
- name: "Run benchmarks"
uses: CodSpeedHQ/action@v2
uses: CodSpeedHQ/action@v1
with:
run: cargo codspeed run
token: ${{ secrets.CODSPEED_TOKEN }}

View File

@@ -20,7 +20,7 @@ jobs:
- uses: actions/checkout@v4
with:
ref: ${{ inputs.ref }}
- uses: actions/setup-python@v5
- uses: actions/setup-python@v4
- name: "Add SSH key"
if: ${{ env.MKDOCS_INSIDERS_SSH_KEY_EXISTS == 'true' }}
uses: webfactory/ssh-agent@v0.8.0

View File

@@ -20,7 +20,7 @@ jobs:
runs-on: macos-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
- uses: actions/setup-python@v4
with:
python-version: ${{ env.PYTHON_VERSION }}
architecture: x64
@@ -43,7 +43,7 @@ jobs:
runs-on: macos-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
- uses: actions/setup-python@v4
with:
python-version: ${{ env.PYTHON_VERSION }}
architecture: x64
@@ -69,7 +69,7 @@ jobs:
target: [x64, x86]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
- uses: actions/setup-python@v4
with:
python-version: ${{ env.PYTHON_VERSION }}
architecture: ${{ matrix.target }}
@@ -97,7 +97,7 @@ jobs:
target: [x86_64, i686]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
- uses: actions/setup-python@v4
with:
python-version: ${{ env.PYTHON_VERSION }}
architecture: x64
@@ -124,7 +124,7 @@ jobs:
target: [aarch64, armv7, s390x, ppc64le, ppc64]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
- uses: actions/setup-python@v4
with:
python-version: ${{ env.PYTHON_VERSION }}
- name: "Build wheels"
@@ -161,7 +161,7 @@ jobs:
- i686-unknown-linux-musl
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
- uses: actions/setup-python@v4
with:
python-version: ${{ env.PYTHON_VERSION }}
architecture: x64
@@ -197,7 +197,7 @@ jobs:
arch: armv7
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
- uses: actions/setup-python@v4
with:
python-version: ${{ env.PYTHON_VERSION }}
- name: "Build wheels"
@@ -237,7 +237,7 @@ jobs:
- uses: actions/download-artifact@v3
with:
name: wheels
- uses: actions/setup-python@v5
- uses: actions/setup-python@v4
- name: "Publish to PyPi"
env:
TWINE_USERNAME: __token__

View File

@@ -17,7 +17,7 @@ jobs:
comment:
runs-on: ubuntu-latest
steps:
- uses: dawidd6/action-download-artifact@v3
- uses: dawidd6/action-download-artifact@v2
name: Download pull request number
with:
name: pr-number
@@ -32,7 +32,7 @@ jobs:
echo "pr-number=$(<pr-number)" >> $GITHUB_OUTPUT
fi
- uses: dawidd6/action-download-artifact@v3
- uses: dawidd6/action-download-artifact@v2
name: "Download ecosystem results"
id: download-ecosystem-result
if: steps.pr-number.outputs.pr-number

View File

@@ -36,7 +36,7 @@ jobs:
- uses: actions/checkout@v4
with:
ref: ${{ inputs.sha }}
- uses: actions/setup-python@v5
- uses: actions/setup-python@v4
with:
python-version: ${{ env.PYTHON_VERSION }}
- name: "Prep README.md"
@@ -63,7 +63,7 @@ jobs:
- uses: actions/checkout@v4
with:
ref: ${{ inputs.sha }}
- uses: actions/setup-python@v5
- uses: actions/setup-python@v4
with:
python-version: ${{ env.PYTHON_VERSION }}
architecture: x64
@@ -73,7 +73,7 @@ jobs:
uses: PyO3/maturin-action@v1
with:
target: x86_64
args: --release --locked --out dist
args: --release --out dist
- name: "Test wheel - x86_64"
run: |
pip install dist/${{ env.PACKAGE_NAME }}-*.whl --force-reinstall
@@ -86,7 +86,7 @@ jobs:
path: dist
- name: "Archive binary"
run: |
ARCHIVE_FILE=ruff-${{ inputs.tag }}-x86_64-apple-darwin.tar.gz
ARCHIVE_FILE=ruff-x86_64-apple-darwin.tar.gz
tar czvf $ARCHIVE_FILE -C target/x86_64-apple-darwin/release ruff
shasum -a 256 $ARCHIVE_FILE > $ARCHIVE_FILE.sha256
- name: "Upload binary"
@@ -103,7 +103,7 @@ jobs:
- uses: actions/checkout@v4
with:
ref: ${{ inputs.sha }}
- uses: actions/setup-python@v5
- uses: actions/setup-python@v4
with:
python-version: ${{ env.PYTHON_VERSION }}
architecture: x64
@@ -112,7 +112,7 @@ jobs:
- name: "Build wheels - universal2"
uses: PyO3/maturin-action@v1
with:
args: --release --locked --target universal2-apple-darwin --out dist
args: --release --target universal2-apple-darwin --out dist
- name: "Test wheel - universal2"
run: |
pip install dist/${{ env.PACKAGE_NAME }}-*universal2.whl --force-reinstall
@@ -125,7 +125,7 @@ jobs:
path: dist
- name: "Archive binary"
run: |
ARCHIVE_FILE=ruff-${{ inputs.tag }}-aarch64-apple-darwin.tar.gz
ARCHIVE_FILE=ruff-aarch64-apple-darwin.tar.gz
tar czvf $ARCHIVE_FILE -C target/aarch64-apple-darwin/release ruff
shasum -a 256 $ARCHIVE_FILE > $ARCHIVE_FILE.sha256
- name: "Upload binary"
@@ -151,7 +151,7 @@ jobs:
- uses: actions/checkout@v4
with:
ref: ${{ inputs.sha }}
- uses: actions/setup-python@v5
- uses: actions/setup-python@v4
with:
python-version: ${{ env.PYTHON_VERSION }}
architecture: ${{ matrix.platform.arch }}
@@ -161,7 +161,7 @@ jobs:
uses: PyO3/maturin-action@v1
with:
target: ${{ matrix.platform.target }}
args: --release --locked --out dist
args: --release --out dist
- name: "Test wheel"
if: ${{ !startsWith(matrix.platform.target, 'aarch64') }}
shell: bash
@@ -177,7 +177,7 @@ jobs:
- name: "Archive binary"
shell: bash
run: |
ARCHIVE_FILE=ruff-${{ inputs.tag }}-${{ matrix.platform.target }}.zip
ARCHIVE_FILE=ruff-${{ matrix.platform.target }}.zip
7z a $ARCHIVE_FILE ./target/${{ matrix.platform.target }}/release/ruff.exe
sha256sum $ARCHIVE_FILE > $ARCHIVE_FILE.sha256
- name: "Upload binary"
@@ -199,7 +199,7 @@ jobs:
- uses: actions/checkout@v4
with:
ref: ${{ inputs.sha }}
- uses: actions/setup-python@v5
- uses: actions/setup-python@v4
with:
python-version: ${{ env.PYTHON_VERSION }}
architecture: x64
@@ -210,7 +210,7 @@ jobs:
with:
target: ${{ matrix.target }}
manylinux: auto
args: --release --locked --out dist
args: --release --out dist
- name: "Test wheel"
if: ${{ startsWith(matrix.target, 'x86_64') }}
run: |
@@ -224,7 +224,7 @@ jobs:
path: dist
- name: "Archive binary"
run: |
ARCHIVE_FILE=ruff-${{ inputs.tag }}-${{ matrix.target }}.tar.gz
ARCHIVE_FILE=ruff-${{ matrix.target }}.tar.gz
tar czvf $ARCHIVE_FILE -C target/${{ matrix.target }}/release ruff
shasum -a 256 $ARCHIVE_FILE > $ARCHIVE_FILE.sha256
- name: "Upload binary"
@@ -258,7 +258,7 @@ jobs:
- uses: actions/checkout@v4
with:
ref: ${{ inputs.sha }}
- uses: actions/setup-python@v5
- uses: actions/setup-python@v4
with:
python-version: ${{ env.PYTHON_VERSION }}
- name: "Prep README.md"
@@ -269,7 +269,7 @@ jobs:
target: ${{ matrix.platform.target }}
manylinux: auto
docker-options: ${{ matrix.platform.maturin_docker_options }}
args: --release --locked --out dist
args: --release --out dist
- uses: uraimo/run-on-arch-action@v2
if: matrix.platform.arch != 'ppc64'
name: Test wheel
@@ -291,7 +291,7 @@ jobs:
path: dist
- name: "Archive binary"
run: |
ARCHIVE_FILE=ruff-${{ inputs.tag }}-${{ matrix.platform.target }}.tar.gz
ARCHIVE_FILE=ruff-${{ matrix.platform.target }}.tar.gz
tar czvf $ARCHIVE_FILE -C target/${{ matrix.platform.target }}/release ruff
shasum -a 256 $ARCHIVE_FILE > $ARCHIVE_FILE.sha256
- name: "Upload binary"
@@ -313,7 +313,7 @@ jobs:
- uses: actions/checkout@v4
with:
ref: ${{ inputs.sha }}
- uses: actions/setup-python@v5
- uses: actions/setup-python@v4
with:
python-version: ${{ env.PYTHON_VERSION }}
architecture: x64
@@ -324,7 +324,7 @@ jobs:
with:
target: ${{ matrix.target }}
manylinux: musllinux_1_2
args: --release --locked --out dist
args: --release --out dist
- name: "Test wheel"
if: matrix.target == 'x86_64-unknown-linux-musl'
uses: addnab/docker-run-action@v3
@@ -332,10 +332,10 @@ jobs:
image: alpine:latest
options: -v ${{ github.workspace }}:/io -w /io
run: |
apk add python3
python -m venv .venv
.venv/bin/pip3 install ${{ env.PACKAGE_NAME }} --no-index --find-links dist/ --force-reinstall
.venv/bin/ruff check --help
apk add py3-pip
pip3 install ${{ env.PACKAGE_NAME }} --no-index --find-links /io/dist/ --force-reinstall
ruff --help
python -m ruff --help
- name: "Upload wheels"
uses: actions/upload-artifact@v3
with:
@@ -343,7 +343,7 @@ jobs:
path: dist
- name: "Archive binary"
run: |
ARCHIVE_FILE=ruff-${{ inputs.tag }}-${{ matrix.target }}.tar.gz
ARCHIVE_FILE=ruff-${{ matrix.target }}.tar.gz
tar czvf $ARCHIVE_FILE -C target/${{ matrix.target }}/release ruff
shasum -a 256 $ARCHIVE_FILE > $ARCHIVE_FILE.sha256
- name: "Upload binary"
@@ -369,7 +369,7 @@ jobs:
- uses: actions/checkout@v4
with:
ref: ${{ inputs.sha }}
- uses: actions/setup-python@v5
- uses: actions/setup-python@v4
with:
python-version: ${{ env.PYTHON_VERSION }}
- name: "Prep README.md"
@@ -379,7 +379,7 @@ jobs:
with:
target: ${{ matrix.platform.target }}
manylinux: musllinux_1_2
args: --release --locked --out dist
args: --release --out dist
docker-options: ${{ matrix.platform.maturin_docker_options }}
- uses: uraimo/run-on-arch-action@v2
name: Test wheel
@@ -388,11 +388,10 @@ jobs:
distro: alpine_latest
githubToken: ${{ github.token }}
install: |
apk add python3
apk add py3-pip
run: |
python -m venv .venv
.venv/bin/pip3 install ${{ env.PACKAGE_NAME }} --no-index --find-links dist/ --force-reinstall
.venv/bin/ruff check --help
pip3 install ${{ env.PACKAGE_NAME }} --no-index --find-links dist/ --force-reinstall
ruff check --help
- name: "Upload wheels"
uses: actions/upload-artifact@v3
with:
@@ -400,7 +399,7 @@ jobs:
path: dist
- name: "Archive binary"
run: |
ARCHIVE_FILE=ruff-${{ inputs.tag }}-${{ matrix.platform.target }}.tar.gz
ARCHIVE_FILE=ruff-${{ matrix.platform.target }}.tar.gz
tar czvf $ARCHIVE_FILE -C target/${{ matrix.platform.target }}/release ruff
shasum -a 256 $ARCHIVE_FILE > $ARCHIVE_FILE.sha256
- name: "Upload binary"

View File

@@ -1,42 +1,5 @@
# Breaking Changes
## 0.1.9
### `site-packages` is now excluded by default ([#5513](https://github.com/astral-sh/ruff/pull/5513))
Ruff maintains a list of default exclusions, which now consists of the following patterns:
- `.bzr`
- `.direnv`
- `.eggs`
- `.git-rewrite`
- `.git`
- `.hg`
- `.ipynb_checkpoints`
- `.mypy_cache`
- `.nox`
- `.pants.d`
- `.pyenv`
- `.pytest_cache`
- `.pytype`
- `.ruff_cache`
- `.svn`
- `.tox`
- `.venv`
- `.vscode`
- `__pypackages__`
- `_build`
- `buck-out`
- `build`
- `dist`
- `node_modules`
- `site-packages`
- `venv`
Previously, the `site-packages` directory was not excluded by default. While `site-packages` tends
to be excluded anyway by virtue of the `.venv` exclusion, this may not be the case when using Ruff
from VS Code outside a virtual environment.
## 0.1.0
### The deprecated `format` setting has been removed

View File

@@ -1,212 +1,5 @@
# Changelog
## 0.1.9
### Breaking changes
- Add site-packages to default exclusions ([#9188](https://github.com/astral-sh/ruff/pull/9188))
### Preview features
- Fix: Avoid parenthesizing subscript targets and values ([#9209](https://github.com/astral-sh/ruff/pull/9209))
- \[`pylint`\] Implement `too-many-locals` (`PLR0914`) ([#9163](https://github.com/astral-sh/ruff/pull/9163))
- Implement `reimplemented_operator` (FURB118) ([#9171](https://github.com/astral-sh/ruff/pull/9171))
- Add a rule to detect string members in runtime-evaluated unions ([#9143](https://github.com/astral-sh/ruff/pull/9143))
- Implement `no_blank_line_before_class_docstring` preview style ([#9154](https://github.com/astral-sh/ruff/pull/9154))
### Rule changes
- `CONSTANT_CASE` variables are improperly flagged for yoda violation (`SIM300`) ([#9164](https://github.com/astral-sh/ruff/pull/9164))
- \[`flake8-pyi`\] Cover ParamSpecs and TypeVarTuples (`PYI018`) ([#9198](https://github.com/astral-sh/ruff/pull/9198))
- \[`flake8-bugbear`\] Add fix for `zip-without-explicit-strict` (`B905`) ([#9176](https://github.com/astral-sh/ruff/pull/9176))
- Add fix to automatically remove `print` and `pprint` statements (`T201`, `T203`) ([#9208](https://github.com/astral-sh/ruff/pull/9208))
- Prefer `Never` to `NoReturn` in auto-typing in Python >= 3.11 (`ANN201`) ([#9213](https://github.com/astral-sh/ruff/pull/9213))
### Formatter
- `can_omit_optional_parentheses`: Exit early for unparenthesized expressions ([#9125](https://github.com/astral-sh/ruff/pull/9125))
- Fix `dynamic` mode with doctests so that it doesn't exceed configured line width ([#9129](https://github.com/astral-sh/ruff/pull/9129))
- Fix `can_omit_optional_parentheses` for expressions with a right most fstring ([#9124](https://github.com/astral-sh/ruff/pull/9124))
- Add `target_version` to formatter options ([#9220](https://github.com/astral-sh/ruff/pull/9220))
### CLI
- Update `ruff format --check` to display message for already formatted files ([#9153](https://github.com/astral-sh/ruff/pull/9153))
### Bug fixes
- Reverse order of arguments for `operator.contains` ([#9192](https://github.com/astral-sh/ruff/pull/9192))
- Iterate over lambdas in deferred type annotations ([#9175](https://github.com/astral-sh/ruff/pull/9175))
- Fix panic in `D208` with multibyte indent ([#9147](https://github.com/astral-sh/ruff/pull/9147))
- Add support for `NoReturn` in auto-return-typing ([#9206](https://github.com/astral-sh/ruff/pull/9206))
- Allow removal of `typing` from `exempt-modules` ([#9214](https://github.com/astral-sh/ruff/pull/9214))
- Avoid `mutable-class-default` violations for Pydantic subclasses ([#9187](https://github.com/astral-sh/ruff/pull/9187))
- Fix dropped union expressions for piped non-types in `PYI055` autofix ([#9161](https://github.com/astral-sh/ruff/pull/9161))
- Enable annotation quoting for multi-line expressions ([#9142](https://github.com/astral-sh/ruff/pull/9142))
- Deduplicate edits when quoting annotations ([#9140](https://github.com/astral-sh/ruff/pull/9140))
- Prevent invalid utf8 indexing in cell magic detection ([#9146](https://github.com/astral-sh/ruff/pull/9146))
- Avoid nested quotations in auto-quoting fix ([#9168](https://github.com/astral-sh/ruff/pull/9168))
- Add base-class inheritance detection to flake8-django rules ([#9151](https://github.com/astral-sh/ruff/pull/9151))
- Avoid `asyncio-dangling-task` violations on shadowed bindings ([#9215](https://github.com/astral-sh/ruff/pull/9215))
### Documentation
- Fix blog post URL in changelog ([#9119](https://github.com/astral-sh/ruff/pull/9119))
- Add error suppression hint for multi-line strings ([#9205](https://github.com/astral-sh/ruff/pull/9205))
- Fix typo in SemanticModel.parent_expression docstring ([#9167](https://github.com/astral-sh/ruff/pull/9167))
- Document link between import sorting and formatter ([#9117](https://github.com/astral-sh/ruff/pull/9117))
## 0.1.8
This release includes opt-in support for formatting Python snippets within
docstrings via the `docstring-code-format` setting.
[Check out the blog post](https://astral.sh/blog/ruff-v0.1.8) for more details!
### Preview features
- Add `"preserve"` quote-style to mimic Black's skip-string-normalization ([#8822](https://github.com/astral-sh/ruff/pull/8822))
- Implement `prefer_splitting_right_hand_side_of_assignments` preview style ([#8943](https://github.com/astral-sh/ruff/pull/8943))
- \[`pycodestyle`\] Add fix for `unexpected-spaces-around-keyword-parameter-equals` ([#9072](https://github.com/astral-sh/ruff/pull/9072))
- \[`pycodestyle`\] Add fix for comment-related whitespace rules ([#9075](https://github.com/astral-sh/ruff/pull/9075))
- \[`pycodestyle`\] Allow `sys.path` modifications between imports ([#9047](https://github.com/astral-sh/ruff/pull/9047))
- \[`refurb`\] Implement `hashlib-digest-hex` (`FURB181`) ([#9077](https://github.com/astral-sh/ruff/pull/9077))
### Rule changes
- Allow `flake8-type-checking` rules to automatically quote runtime-evaluated references ([#6001](https://github.com/astral-sh/ruff/pull/6001))
- Allow transparent cell magics in Jupyter Notebooks ([#8911](https://github.com/astral-sh/ruff/pull/8911))
- \[`flake8-annotations`\] Avoid `ANN2xx` fixes for abstract methods with empty bodies ([#9034](https://github.com/astral-sh/ruff/pull/9034))
- \[`flake8-self`\] Ignore underscore references in type annotations ([#9036](https://github.com/astral-sh/ruff/pull/9036))
- \[`pep8-naming`\] Allow class names when `apps.get_model` is a non-string ([#9065](https://github.com/astral-sh/ruff/pull/9065))
- \[`pycodestyle`\] Allow `matplotlib.use` calls to intersperse imports ([#9094](https://github.com/astral-sh/ruff/pull/9094))
- \[`pyflakes`\] Support fixing unused assignments in tuples by renaming variables (`F841`) ([#9107](https://github.com/astral-sh/ruff/pull/9107))
- \[`pylint`\] Add fix for `subprocess-run-without-check` (`PLW1510`) ([#6708](https://github.com/astral-sh/ruff/pull/6708))
### Formatter
- Add `docstring-code-format` knob to enable docstring snippet formatting ([#8854](https://github.com/astral-sh/ruff/pull/8854))
- Use double quotes for all docstrings, including single-quoted docstrings ([#9020](https://github.com/astral-sh/ruff/pull/9020))
- Implement "dynamic" line width mode for docstring code formatting ([#9098](https://github.com/astral-sh/ruff/pull/9098))
- Support reformatting Markdown code blocks ([#9030](https://github.com/astral-sh/ruff/pull/9030))
- add support for formatting reStructuredText code snippets ([#9003](https://github.com/astral-sh/ruff/pull/9003))
- Avoid trailing comma for single-argument with positional separator ([#9076](https://github.com/astral-sh/ruff/pull/9076))
- Fix handling of trailing target comment ([#9051](https://github.com/astral-sh/ruff/pull/9051))
### CLI
- Hide unsafe fix suggestions when explicitly disabled ([#9095](https://github.com/astral-sh/ruff/pull/9095))
- Add SARIF support to `--output-format` ([#9078](https://github.com/astral-sh/ruff/pull/9078))
### Bug fixes
- Apply unnecessary index rule prior to enumerate rewrite ([#9012](https://github.com/astral-sh/ruff/pull/9012))
- \[`flake8-err-msg`\] Allow `EM` fixes even if `msg` variable is defined ([#9059](https://github.com/astral-sh/ruff/pull/9059))
- \[`flake8-pie`\] Prevent keyword arguments duplication ([#8450](https://github.com/astral-sh/ruff/pull/8450))
- \[`flake8-pie`\] Respect trailing comma in `unnecessary-dict-kwargs` (`PIE804`) ([#9015](https://github.com/astral-sh/ruff/pull/9015))
- \[`flake8-raise`\] Avoid removing parentheses on ctypes.WinError ([#9027](https://github.com/astral-sh/ruff/pull/9027))
- \[`isort`\] Avoid invalid combination of `force-sort-within-types` and `lines-between-types` ([#9041](https://github.com/astral-sh/ruff/pull/9041))
- \[`isort`\] Ensure that from-style imports are always ordered first in `__future__` ([#9039](https://github.com/astral-sh/ruff/pull/9039))
- \[`pycodestyle`\] Allow tab indentation before keyword ([#9099](https://github.com/astral-sh/ruff/pull/9099))
- \[`pylint`\] Ignore `@overrides` and `@overloads` for `too-many-positional` ([#9000](https://github.com/astral-sh/ruff/pull/9000))
- \[`pyupgrade`\] Enable `printf-string-formatting` fix with comments on right-hand side ([#9037](https://github.com/astral-sh/ruff/pull/9037))
- \[`refurb`\] Make `math-constant` (`FURB152`) rule more targeted ([#9054](https://github.com/astral-sh/ruff/pull/9054))
- \[`refurb`\] Support floating-point base in `redundant-log-base` (`FURB163`) ([#9100](https://github.com/astral-sh/ruff/pull/9100))
- \[`ruff`\] Detect `unused-asyncio-dangling-task` (`RUF006`) on unused assignments ([#9060](https://github.com/astral-sh/ruff/pull/9060))
## 0.1.7
### Preview features
- Implement multiline dictionary and list hugging for preview style ([#8293](https://github.com/astral-sh/ruff/pull/8293))
- Implement the `fix_power_op_line_length` preview style ([#8947](https://github.com/astral-sh/ruff/pull/8947))
- Use Python version to determine typing rewrite safety ([#8919](https://github.com/astral-sh/ruff/pull/8919))
- \[`flake8-annotations`\] Enable auto-return-type involving `Optional` and `Union` annotations ([#8885](https://github.com/astral-sh/ruff/pull/8885))
- \[`flake8-bandit`\] Implement `django-raw-sql` (`S611`) ([#8651](https://github.com/astral-sh/ruff/pull/8651))
- \[`flake8-bandit`\] Implement `tarfile-unsafe-members` (`S202`) ([#8829](https://github.com/astral-sh/ruff/pull/8829))
- \[`flake8-pyi`\] Implement fix for `unnecessary-literal-union` (`PYI030`) ([#7934](https://github.com/astral-sh/ruff/pull/7934))
- \[`flake8-simplify`\] Extend `dict-get-with-none-default` (`SIM910`) to non-literals ([#8762](https://github.com/astral-sh/ruff/pull/8762))
- \[`pylint`\] - add `unnecessary-list-index-lookup` (`PLR1736`) + autofix ([#7999](https://github.com/astral-sh/ruff/pull/7999))
- \[`pylint`\] - implement R0202 and R0203 with autofixes ([#8335](https://github.com/astral-sh/ruff/pull/8335))
- \[`pylint`\] Implement `repeated-keyword` (`PLe1132`) ([#8706](https://github.com/astral-sh/ruff/pull/8706))
- \[`pylint`\] Implement `too-many-positional` (`PLR0917`) ([#8995](https://github.com/astral-sh/ruff/pull/8995))
- \[`pylint`\] Implement `unnecessary-dict-index-lookup` (`PLR1733`) ([#8036](https://github.com/astral-sh/ruff/pull/8036))
- \[`refurb`\] Implement `redundant-log-base` (`FURB163`) ([#8842](https://github.com/astral-sh/ruff/pull/8842))
### Rule changes
- \[`flake8-boolean-trap`\] Allow booleans in `@override` methods ([#8882](https://github.com/astral-sh/ruff/pull/8882))
- \[`flake8-bugbear`\] Avoid `B015`,`B018` for last expression in a cell ([#8815](https://github.com/astral-sh/ruff/pull/8815))
- \[`flake8-pie`\] Allow ellipses for enum values in stub files ([#8825](https://github.com/astral-sh/ruff/pull/8825))
- \[`flake8-pyi`\] Check PEP 695 type aliases for `snake-case-type-alias` and `t-suffixed-type-alias` ([#8966](https://github.com/astral-sh/ruff/pull/8966))
- \[`flake8-pyi`\] Check for kwarg and vararg `NoReturn` type annotations ([#8948](https://github.com/astral-sh/ruff/pull/8948))
- \[`flake8-simplify`\] Omit select context managers from `SIM117` ([#8801](https://github.com/astral-sh/ruff/pull/8801))
- \[`pep8-naming`\] Allow Django model loads in `non-lowercase-variable-in-function` (`N806`) ([#8917](https://github.com/astral-sh/ruff/pull/8917))
- \[`pycodestyle`\] Avoid `E703` for last expression in a cell ([#8821](https://github.com/astral-sh/ruff/pull/8821))
- \[`pycodestyle`\] Update `E402` to work at cell level for notebooks ([#8872](https://github.com/astral-sh/ruff/pull/8872))
- \[`pydocstyle`\] Avoid `D100` for Jupyter Notebooks ([#8816](https://github.com/astral-sh/ruff/pull/8816))
- \[`pylint`\] Implement fix for `unspecified-encoding` (`PLW1514`) ([#8928](https://github.com/astral-sh/ruff/pull/8928))
### Formatter
- Avoid unstable formatting in ellipsis-only body with trailing comment ([#8984](https://github.com/astral-sh/ruff/pull/8984))
- Inline trailing comments for type alias similar to assignments ([#8941](https://github.com/astral-sh/ruff/pull/8941))
- Insert trailing comma when function breaks with single argument ([#8921](https://github.com/astral-sh/ruff/pull/8921))
### CLI
- Update `ruff check` and `ruff format` to default to the current directory ([#8791](https://github.com/astral-sh/ruff/pull/8791))
- Stop at the first resolved parent configuration ([#8864](https://github.com/astral-sh/ruff/pull/8864))
### Configuration
- \[`pylint`\] Default `max-positional-args` to `max-args` ([#8998](https://github.com/astral-sh/ruff/pull/8998))
- \[`pylint`\] Add `allow-dunder-method-names` setting for `bad-dunder-method-name` (`PLW3201`) ([#8812](https://github.com/astral-sh/ruff/pull/8812))
- \[`isort`\] Add support for `from-first` setting ([#8663](https://github.com/astral-sh/ruff/pull/8663))
- \[`isort`\] Add support for `length-sort` settings ([#8841](https://github.com/astral-sh/ruff/pull/8841))
### Bug fixes
- Add support for `@functools.singledispatch` ([#8934](https://github.com/astral-sh/ruff/pull/8934))
- Avoid off-by-one error in stripping noqa following multi-byte char ([#8979](https://github.com/astral-sh/ruff/pull/8979))
- Avoid off-by-one error in with-item named expressions ([#8915](https://github.com/astral-sh/ruff/pull/8915))
- Avoid syntax error via invalid ur string prefix ([#8971](https://github.com/astral-sh/ruff/pull/8971))
- Avoid underflow in `get_model` matching ([#8965](https://github.com/astral-sh/ruff/pull/8965))
- Avoid unnecessary index diagnostics when value is modified ([#8970](https://github.com/astral-sh/ruff/pull/8970))
- Convert over-indentation rule to use number of characters ([#8983](https://github.com/astral-sh/ruff/pull/8983))
- Detect implicit returns in auto-return-types ([#8952](https://github.com/astral-sh/ruff/pull/8952))
- Fix start >= end error in over-indentation ([#8982](https://github.com/astral-sh/ruff/pull/8982))
- Ignore `@overload` and `@override` methods for too-many-arguments checks ([#8954](https://github.com/astral-sh/ruff/pull/8954))
- Lexer start of line is false only for `Mode::Expression` ([#8880](https://github.com/astral-sh/ruff/pull/8880))
- Mark `pydantic_settings.BaseSettings` as having default copy semantics ([#8793](https://github.com/astral-sh/ruff/pull/8793))
- Respect dictionary unpacking in `NamedTuple` assignments ([#8810](https://github.com/astral-sh/ruff/pull/8810))
- Respect local subclasses in `flake8-type-checking` ([#8768](https://github.com/astral-sh/ruff/pull/8768))
- Support type alias statements in simple statement positions ([#8916](https://github.com/astral-sh/ruff/pull/8916))
- \[`flake8-annotations`\] Avoid filtering out un-representable types in return annotation ([#8881](https://github.com/astral-sh/ruff/pull/8881))
- \[`flake8-pie`\] Retain extra ellipses in protocols and abstract methods ([#8769](https://github.com/astral-sh/ruff/pull/8769))
- \[`flake8-pyi`\] Respect local enum subclasses in `simple-defaults` (`PYI052`) ([#8767](https://github.com/astral-sh/ruff/pull/8767))
- \[`flake8-trio`\] Use correct range for `TRIO115` fix ([#8933](https://github.com/astral-sh/ruff/pull/8933))
- \[`flake8-trio`\] Use full arguments range for zero-sleep-call ([#8936](https://github.com/astral-sh/ruff/pull/8936))
- \[`isort`\] fix: mark `__main__` as first-party import ([#8805](https://github.com/astral-sh/ruff/pull/8805))
- \[`pep8-naming`\] Avoid `N806` errors for type alias statements ([#8785](https://github.com/astral-sh/ruff/pull/8785))
- \[`perflint`\] Avoid `PERF101` if there's an append in loop body ([#8809](https://github.com/astral-sh/ruff/pull/8809))
- \[`pycodestyle`\] Allow space-before-colon after end-of-slice ([#8838](https://github.com/astral-sh/ruff/pull/8838))
- \[`pydocstyle`\] Avoid non-character breaks in `over-indentation` (`D208`) ([#8866](https://github.com/astral-sh/ruff/pull/8866))
- \[`pydocstyle`\] Ignore underlines when determining docstring logical lines ([#8929](https://github.com/astral-sh/ruff/pull/8929))
- \[`pylint`\] Extend `self-assigning-variable` to multi-target assignments ([#8839](https://github.com/astral-sh/ruff/pull/8839))
- \[`tryceratops`\] Avoid repeated triggers in nested `tryceratops` diagnostics ([#8772](https://github.com/astral-sh/ruff/pull/8772))
### Documentation
- Add advice for fixing RUF008 when mutability is not desired ([#8853](https://github.com/astral-sh/ruff/pull/8853))
- Added the command to run ruff using pkgx to the installation.md ([#8955](https://github.com/astral-sh/ruff/pull/8955))
- Document fix safety for flake8-comprehensions and some pyupgrade rules ([#8918](https://github.com/astral-sh/ruff/pull/8918))
- Fix doc formatting for zero-sleep-call ([#8937](https://github.com/astral-sh/ruff/pull/8937))
- Remove duplicate imports from os-stat documentation ([#8930](https://github.com/astral-sh/ruff/pull/8930))
- Replace generated reference to MkDocs ([#8806](https://github.com/astral-sh/ruff/pull/8806))
- Update Arch Linux package URL in installation.md ([#8802](https://github.com/astral-sh/ruff/pull/8802))
- \[`flake8-pyi`\] Fix error in `t-suffixed-type-alias` (`PYI043`) example ([#8963](https://github.com/astral-sh/ruff/pull/8963))
- \[`flake8-pyi`\] Improve motivation for `custom-type-var-return-type` (`PYI019`) ([#8766](https://github.com/astral-sh/ruff/pull/8766))
## 0.1.6
### Preview features

View File

@@ -326,18 +326,16 @@ We use an experimental in-house tool for managing releases.
- Often labels will be missing from pull requests they will need to be manually organized into the proper section
- Changes should be edited to be user-facing descriptions, avoiding internal details
1. Highlight any breaking changes in `BREAKING_CHANGES.md`
1. Run `cargo check`. This should update the lock file with new versions.
1. Create a pull request with the changelog and version updates
1. Merge the PR
1. Run the [release workflow](https://github.com/astral-sh/ruff/actions/workflows/release.yaml) with:
- The new version number (without starting `v`)
- The commit hash of the merged release pull request on `main`
1. Run the release workflow with the version number (without starting `v`) as input. Make sure
main has your merged PR as last commit
1. The release workflow will do the following:
1. Build all the assets. If this fails (even though we tested in step 4), we haven't tagged or
uploaded anything, you can restart after pushing a fix.
1. Upload to PyPI.
1. Create and push the Git tag (as extracted from `pyproject.toml`). We create the Git tag only
after building the wheels and uploading to PyPI, since we can't delete or modify the tag ([#4468](https://github.com/astral-sh/ruff/issues/4468)).
after building the wheels and uploading to PyPI, since we can't delete or modify the tag ([#4468](https://github.com/charliermarsh/ruff/issues/4468)).
1. Attach artifacts to draft GitHub release
1. Trigger downstream repositories. This can fail non-catastrophically, as we can run any
downstream jobs manually if needed.
@@ -346,10 +344,7 @@ We use an experimental in-house tool for managing releases.
1. Copy the changelog for the release into the GitHub release
- See previous releases for formatting of section headers
1. Generate the contributor list with `rooster contributors` and add to the release notes
1. If needed, [update the schemastore](https://github.com/astral-sh/ruff/blob/main/scripts/update_schemastore.py).
1. One can determine if an update is needed when
`git diff old-version-tag new-version-tag -- ruff.schema.json` returns a non-empty diff.
1. Once run successfully, you should follow the link in the output to create a PR.
1. If needed, [update the schemastore](https://github.com/charliermarsh/ruff/blob/main/scripts/update_schemastore.py)
1. If needed, update the `ruff-lsp` and `ruff-vscode` repositories.
## Ecosystem CI
@@ -561,10 +556,10 @@ examples.
#### Linux
Install `perf` and build `ruff_benchmark` with the `profiling` profile and then run it with perf
Install `perf` and build `ruff_benchmark` with the `release-debug` profile and then run it with perf
```shell
cargo bench -p ruff_benchmark --no-run --profile=profiling && perf record --call-graph dwarf -F 9999 cargo bench -p ruff_benchmark --profile=profiling -- --profile-time=1
cargo bench -p ruff_benchmark --no-run --profile=release-debug && perf record --call-graph dwarf -F 9999 cargo bench -p ruff_benchmark --profile=release-debug -- --profile-time=1
```
You can also use the `ruff_dev` launcher to run `ruff check` multiple times on a repository to
@@ -572,8 +567,8 @@ gather enough samples for a good flamegraph (change the 999, the sample rate, an
of checks, to your liking)
```shell
cargo build --bin ruff_dev --profile=profiling
perf record -g -F 999 target/profiling/ruff_dev repeat --repeat 30 --exit-zero --no-cache path/to/cpython > /dev/null
cargo build --bin ruff_dev --profile=release-debug
perf record -g -F 999 target/release-debug/ruff_dev repeat --repeat 30 --exit-zero --no-cache path/to/cpython > /dev/null
```
Then convert the recorded profile
@@ -603,7 +598,7 @@ cargo install cargo-instruments
Then run the profiler with
```shell
cargo instruments -t time --bench linter --profile profiling -p ruff_benchmark -- --profile-time=1
cargo instruments -t time --bench linter --profile release-debug -p ruff_benchmark -- --profile-time=1
```
- `-t`: Specifies what to profile. Useful options are `time` to profile the wall time and `alloc`

363
Cargo.lock generated
View File

@@ -16,15 +16,14 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
[[package]]
name = "ahash"
version = "0.8.6"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "91429305e9f0a25f6205c5b8e0d2db09e0708a7a6df0f42212bb56c32c8ac97a"
checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f"
dependencies = [
"cfg-if",
"getrandom",
"once_cell",
"version_check",
"zerocopy",
]
[[package]]
@@ -123,9 +122,9 @@ dependencies = [
[[package]]
name = "anyhow"
version = "1.0.76"
version = "1.0.75"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "59d2a3357dde987206219e78ecfbbb6e8dad06cbb65292758d3270e6254f7355"
checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6"
[[package]]
name = "argfile"
@@ -234,9 +233,9 @@ checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1"
[[package]]
name = "cachedir"
version = "0.3.1"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4703f3937077db8fa35bee3c8789343c1aec2585f0146f09d658d4ccc0e8d873"
checksum = "e236bf5873ea57ec2877445297f4da008916bfae51567131acfc54a073d694f3"
dependencies = [
"tempfile",
]
@@ -382,7 +381,7 @@ dependencies = [
"heck",
"proc-macro2",
"quote",
"syn 2.0.40",
"syn 2.0.39",
]
[[package]]
@@ -434,10 +433,11 @@ checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
[[package]]
name = "colored"
version = "2.1.0"
version = "2.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cbf2150cce219b664a8a70df7a1f933836724b503f8a413af9365b4dcc4d90b8"
checksum = "2674ec482fbc38012cf31e6c42ba0177b431a0cb6f15fe40efa5aab1bda516f6"
dependencies = [
"is-terminal",
"lazy_static",
"windows-sys 0.48.0",
]
@@ -606,7 +606,7 @@ dependencies = [
"proc-macro2",
"quote",
"strsim",
"syn 2.0.40",
"syn 2.0.39",
]
[[package]]
@@ -617,7 +617,7 @@ checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5"
dependencies = [
"darling_core",
"quote",
"syn 2.0.40",
"syn 2.0.39",
]
[[package]]
@@ -735,9 +735,9 @@ checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f"
[[package]]
name = "env_logger"
version = "0.10.1"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95b3f3e67048839cb0d0781f445682a35113da7121f7c949db0e2be96a4fbece"
checksum = "85cdab6a89accf66733ad5a1693a4dcced6aeff64602b634530dd73c1f3ee9f0"
dependencies = [
"humantime",
"is-terminal",
@@ -790,14 +790,14 @@ dependencies = [
[[package]]
name = "filetime"
version = "0.2.23"
version = "0.2.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd"
checksum = "d4029edd3e734da6fe05b6cd7bd2960760a616bd2ddd0d59a0124746d6272af0"
dependencies = [
"cfg-if",
"libc",
"redox_syscall 0.4.1",
"windows-sys 0.52.0",
"redox_syscall 0.3.5",
"windows-sys 0.48.0",
]
[[package]]
@@ -808,7 +808,7 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
[[package]]
name = "flake8-to-ruff"
version = "0.1.9"
version = "0.1.6"
dependencies = [
"anyhow",
"clap",
@@ -817,7 +817,7 @@ dependencies = [
"itertools 0.11.0",
"log",
"once_cell",
"pep440_rs 0.4.0",
"pep440_rs",
"pretty_assertions",
"regex",
"ruff_linter",
@@ -827,7 +827,7 @@ dependencies = [
"serde_json",
"strum",
"strum_macros",
"toml",
"toml 0.7.8",
]
[[package]]
@@ -848,18 +848,18 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
[[package]]
name = "form_urlencoded"
version = "1.2.1"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456"
checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652"
dependencies = [
"percent-encoding",
]
[[package]]
name = "fs-err"
version = "2.11.0"
version = "2.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "88a41f105fe1d5b6b34b2055e3dc59bb79b46b48b2040b9e6c7b4b5de097aa41"
checksum = "fb5fd9bcbe8b1087cbd395b51498c01bc997cef73e778a80b77a811af5e2d29f"
dependencies = [
"autocfg",
]
@@ -987,9 +987,9 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
[[package]]
name = "idna"
version = "0.5.0"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6"
checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c"
dependencies = [
"unicode-bidi",
"unicode-normalization",
@@ -997,16 +997,17 @@ dependencies = [
[[package]]
name = "ignore"
version = "0.4.21"
version = "0.4.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "747ad1b4ae841a78e8aba0d63adbfbeaea26b517b63705d47856b73015d27060"
checksum = "dbe7873dab538a9a44ad79ede1faf5f30d49f9a5c883ddbab48bce81b64b7492"
dependencies = [
"crossbeam-deque",
"globset",
"lazy_static",
"log",
"memchr",
"regex-automata 0.4.3",
"regex",
"same-file",
"thread_local",
"walkdir",
"winapi-util",
]
@@ -1121,15 +1122,15 @@ dependencies = [
[[package]]
name = "is-macro"
version = "0.3.1"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc74b7abae208af9314a406bd7dcc65091230b6e749c09e07a645885fecf34f9"
checksum = "f4467ed1321b310c2625c5aa6c1b1ffc5de4d9e42668cf697a08fb033ee8265e"
dependencies = [
"Inflector",
"pmutil 0.6.1",
"proc-macro2",
"quote",
"syn 2.0.40",
"syn 2.0.39",
]
[[package]]
@@ -1169,9 +1170,9 @@ checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38"
[[package]]
name = "js-sys"
version = "0.3.66"
version = "0.3.65"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cee9c64da59eae3b50095c18d3e74f8b73c0b86d2792824ff01bbce68ba229ca"
checksum = "54c0c35952f67de54bb584e9fd912b3023117cbafc0a77d8f3dee1fb5f572fe8"
dependencies = [
"wasm-bindgen",
]
@@ -1480,9 +1481,9 @@ checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3"
[[package]]
name = "once_cell"
version = "1.19.0"
version = "1.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
[[package]]
name = "oorandom"
@@ -1603,18 +1604,6 @@ dependencies = [
"unicode-width",
]
[[package]]
name = "pep440_rs"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e0c29f9c43de378b4e4e0cd7dbcce0e5cfb80443de8c05620368b2948bc936a1"
dependencies = [
"once_cell",
"regex",
"serde",
"unicode-width",
]
[[package]]
name = "pep508_rs"
version = "0.2.1"
@@ -1622,7 +1611,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0713d7bb861ca2b7d4c50a38e1f31a4b63a2e2df35ef1e5855cc29e108453e2"
dependencies = [
"once_cell",
"pep440_rs 0.3.12",
"pep440_rs",
"regex",
"serde",
"thiserror",
@@ -1633,9 +1622,9 @@ dependencies = [
[[package]]
name = "percent-encoding"
version = "2.3.1"
version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94"
[[package]]
name = "petgraph"
@@ -1719,7 +1708,7 @@ checksum = "52a40bc70c2c58040d2d8b167ba9a5ff59fc9dab7ad44771cfde3dcfde7a09c6"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.40",
"syn 2.0.39",
]
[[package]]
@@ -1804,9 +1793,9 @@ dependencies = [
[[package]]
name = "proc-macro2"
version = "1.0.71"
version = "1.0.70"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75cb1540fadbd5b8fbccc4dddad2734eba435053f725621c070711a14bb5f4b8"
checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b"
dependencies = [
"unicode-ident",
]
@@ -1818,10 +1807,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46d4a5e69187f23a29f8aa0ea57491d104ba541bc55f76552c2a74962aa20e04"
dependencies = [
"indexmap",
"pep440_rs 0.3.12",
"pep440_rs",
"pep508_rs",
"serde",
"toml",
"toml 0.8.2",
]
[[package]]
@@ -2073,7 +2062,7 @@ dependencies = [
[[package]]
name = "ruff_cli"
version = "0.1.9"
version = "0.1.6"
dependencies = [
"annotate-snippets 0.9.2",
"anyhow",
@@ -2165,7 +2154,7 @@ dependencies = [
"strum",
"strum_macros",
"tempfile",
"toml",
"toml 0.7.8",
"tracing",
"tracing-indicatif",
"tracing-subscriber",
@@ -2209,7 +2198,7 @@ dependencies = [
[[package]]
name = "ruff_linter"
version = "0.1.9"
version = "0.1.6"
dependencies = [
"aho-corasick",
"annotate-snippets 0.9.2",
@@ -2232,7 +2221,7 @@ dependencies = [
"once_cell",
"path-absolutize",
"pathdiff",
"pep440_rs 0.4.0",
"pep440_rs",
"pretty_assertions",
"pyproject-toml",
"quick-junit",
@@ -2265,11 +2254,10 @@ dependencies = [
"tempfile",
"test-case",
"thiserror",
"toml",
"toml 0.7.8",
"typed-arena",
"unicode-width",
"unicode_names2",
"url",
"wsl",
]
@@ -2281,7 +2269,7 @@ dependencies = [
"proc-macro2",
"quote",
"ruff_python_trivia",
"syn 2.0.40",
"syn 2.0.39",
]
[[package]]
@@ -2462,7 +2450,7 @@ dependencies = [
[[package]]
name = "ruff_shrinking"
version = "0.1.9"
version = "0.1.6"
dependencies = [
"anyhow",
"clap",
@@ -2538,7 +2526,7 @@ dependencies = [
"log",
"once_cell",
"path-absolutize",
"pep440_rs 0.4.0",
"pep440_rs",
"regex",
"ruff_cache",
"ruff_formatter",
@@ -2553,7 +2541,7 @@ dependencies = [
"shellexpand",
"strum",
"tempfile",
"toml",
"toml 0.7.8",
]
[[package]]
@@ -2630,9 +2618,9 @@ dependencies = [
[[package]]
name = "schemars"
version = "0.8.16"
version = "0.8.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "45a28f4c49489add4ce10783f7911893516f15afe45d015608d41faca6bc4d29"
checksum = "1f7b0ce13155372a76ee2e1c5ffba1fe61ede73fbea5630d61eee6fac4929c0c"
dependencies = [
"dyn-clone",
"schemars_derive",
@@ -2642,9 +2630,9 @@ dependencies = [
[[package]]
name = "schemars_derive"
version = "0.8.16"
version = "0.8.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c767fd6fa65d9ccf9cf026122c1b555f2ef9a4f0cea69da4d7dbc3e258d30967"
checksum = "e85e2a16b12bdb763244c69ab79363d71db2b4b918a2def53f80b02e0574b13c"
dependencies = [
"proc-macro2",
"quote",
@@ -2688,18 +2676,18 @@ checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090"
[[package]]
name = "serde"
version = "1.0.193"
version = "1.0.190"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89"
checksum = "91d3c334ca1ee894a2c6f6ad698fe8c435b76d504b13d436f0685d648d6d96f7"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde-wasm-bindgen"
version = "0.6.3"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9b713f70513ae1f8d92665bbbbda5c295c2cf1da5542881ae5eefe20c9af132"
checksum = "17ba92964781421b6cef36bf0d7da26d201e96d84e1b10e7ae6ed416e516906d"
dependencies = [
"js-sys",
"serde",
@@ -2708,13 +2696,13 @@ dependencies = [
[[package]]
name = "serde_derive"
version = "1.0.193"
version = "1.0.190"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3"
checksum = "67c5609f394e5c2bd7fc51efda478004ea80ef42fee983d5c67a65e34f32c0e3"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.40",
"syn 2.0.39",
]
[[package]]
@@ -2741,9 +2729,9 @@ dependencies = [
[[package]]
name = "serde_spanned"
version = "0.6.5"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eb3622f419d1296904700073ea6cc23ad690adbd66f13ea683df73298736f0c1"
checksum = "96426c9936fd7a0124915f9185ea1d20aa9445cc9821142f0a73bc9207a2e186"
dependencies = [
"serde",
]
@@ -2776,7 +2764,7 @@ dependencies = [
"darling",
"proc-macro2",
"quote",
"syn 2.0.40",
"syn 2.0.39",
]
[[package]]
@@ -2880,7 +2868,7 @@ dependencies = [
"proc-macro2",
"quote",
"rustversion",
"syn 2.0.40",
"syn 2.0.39",
]
[[package]]
@@ -2896,9 +2884,9 @@ dependencies = [
[[package]]
name = "syn"
version = "2.0.40"
version = "2.0.39"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13fa70a4ee923979ffb522cacce59d34421ebdea5625e1073c4326ef9d2dd42e"
checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a"
dependencies = [
"proc-macro2",
"quote",
@@ -2968,9 +2956,9 @@ checksum = "3369f5ac52d5eb6ab48c6b4ffdc8efbcad6b89c765749064ba298f2c68a16a76"
[[package]]
name = "test-case"
version = "3.3.1"
version = "3.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eb2550dd13afcd286853192af8601920d959b14c401fcece38071d53bf0768a8"
checksum = "c8f1e820b7f1d95a0cdbf97a5df9de10e1be731983ab943e56703ac1b8e9d425"
dependencies = [
"test-case-macros",
]
@@ -2985,7 +2973,7 @@ dependencies = [
"proc-macro-error",
"proc-macro2",
"quote",
"syn 2.0.40",
"syn 2.0.39",
]
[[package]]
@@ -2997,28 +2985,28 @@ dependencies = [
"proc-macro-error",
"proc-macro2",
"quote",
"syn 2.0.40",
"syn 2.0.39",
"test-case-core",
]
[[package]]
name = "thiserror"
version = "1.0.51"
version = "1.0.50"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f11c217e1416d6f036b870f14e0413d480dbf28edbee1f877abaf0206af43bb7"
checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.51"
version = "1.0.50"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "01742297787513b79cf8e29d1056ede1313e2420b7b3b15d0a768b4921f549df"
checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.40",
"syn 2.0.39",
]
[[package]]
@@ -3103,30 +3091,55 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
[[package]]
name = "toml"
version = "0.8.8"
version = "0.7.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1a195ec8c9da26928f773888e0742ca3ca1040c6cd859c919c9f59c1954ab35"
checksum = "dd79e69d3b627db300ff956027cc6c3798cef26d22526befdfcd12feeb6d2257"
dependencies = [
"serde",
"serde_spanned",
"toml_datetime",
"toml_edit",
"toml_edit 0.19.15",
]
[[package]]
name = "toml"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "185d8ab0dfbb35cf1399a6344d8484209c088f75f8f68230da55d48d95d43e3d"
dependencies = [
"serde",
"serde_spanned",
"toml_datetime",
"toml_edit 0.20.2",
]
[[package]]
name = "toml_datetime"
version = "0.6.5"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1"
checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b"
dependencies = [
"serde",
]
[[package]]
name = "toml_edit"
version = "0.21.0"
version = "0.19.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d34d383cd00a163b4a5b85053df514d45bc330f6de7737edfe0a93311d1eaa03"
checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421"
dependencies = [
"indexmap",
"serde",
"serde_spanned",
"toml_datetime",
"winnow",
]
[[package]]
name = "toml_edit"
version = "0.20.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338"
dependencies = [
"indexmap",
"serde",
@@ -3155,7 +3168,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.40",
"syn 2.0.39",
]
[[package]]
@@ -3170,9 +3183,9 @@ dependencies = [
[[package]]
name = "tracing-indicatif"
version = "0.3.6"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "069580424efe11d97c3fef4197fa98c004fa26672cc71ad8770d224e23b1951d"
checksum = "57e05fe4a1c906d94b275d8aeb8ff8b9deaca502aeb59ae8ab500a92b8032ac8"
dependencies = [
"indicatif",
"tracing",
@@ -3292,9 +3305,9 @@ checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c"
[[package]]
name = "unicode_names2"
version = "1.2.1"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac64ef2f016dc69dfa8283394a70b057066eb054d5fcb6b9eb17bd2ec5097211"
checksum = "5d5506ae2c3c1ccbdf468e52fc5ef536c2ccd981f01273a4cb81aa61021f3a5f"
dependencies = [
"phf",
"unicode_names2_generator",
@@ -3302,9 +3315,9 @@ dependencies = [
[[package]]
name = "unicode_names2_generator"
version = "1.2.1"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "013f6a731e80f3930de580e55ba41dfa846de4e0fdee4a701f97989cb1597d6a"
checksum = "b6dfc680313e95bc6637fa278cd7a22390c3c2cd7b8b2bd28755bc6c0fc811e7"
dependencies = [
"getopts",
"log",
@@ -3321,9 +3334,9 @@ checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a"
[[package]]
name = "ureq"
version = "2.9.1"
version = "2.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8cdd25c339e200129fe4de81451814e5228c9b771d57378817d6117cc2b3f97"
checksum = "f5ccd538d4a604753ebc2f17cd9946e89b77bf87f6a8e2309667c6f2e87855e3"
dependencies = [
"base64",
"flate2",
@@ -3337,9 +3350,9 @@ dependencies = [
[[package]]
name = "url"
version = "2.5.0"
version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633"
checksum = "143b538f18257fac9cad154828a57c6bf5157e1aa604d4816b5995bf6de87ae5"
dependencies = [
"form_urlencoded",
"idna",
@@ -3373,7 +3386,7 @@ checksum = "f49e7f3f3db8040a100710a11932239fd30697115e2ba4107080d8252939845e"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.40",
"syn 2.0.39",
]
[[package]]
@@ -3448,9 +3461,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "wasm-bindgen"
version = "0.2.89"
version = "0.2.88"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ed0d4f68a3015cc185aff4db9506a015f4b96f95303897bfa23f846db54064e"
checksum = "7daec296f25a1bae309c0cd5c29c4b260e510e6d813c286b19eaadf409d40fce"
dependencies = [
"cfg-if",
"wasm-bindgen-macro",
@@ -3458,24 +3471,24 @@ dependencies = [
[[package]]
name = "wasm-bindgen-backend"
version = "0.2.89"
version = "0.2.88"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b56f625e64f3a1084ded111c4d5f477df9f8c92df113852fa5a374dbda78826"
checksum = "e397f4664c0e4e428e8313a469aaa58310d302159845980fd23b0f22a847f217"
dependencies = [
"bumpalo",
"log",
"once_cell",
"proc-macro2",
"quote",
"syn 2.0.40",
"syn 2.0.39",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-futures"
version = "0.4.39"
version = "0.4.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac36a15a220124ac510204aec1c3e5db8a22ab06fd6706d881dc6149f8ed9a12"
checksum = "9afec9963e3d0994cac82455b2b3502b81a7f40f9a0d32181f7528d9f4b43e02"
dependencies = [
"cfg-if",
"js-sys",
@@ -3485,9 +3498,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.89"
version = "0.2.88"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0162dbf37223cd2afce98f3d0785506dcb8d266223983e4b5b525859e6e182b2"
checksum = "5961017b3b08ad5f3fe39f1e79877f8ee7c23c5e5fd5eb80de95abc41f1f16b2"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
@@ -3495,28 +3508,28 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.89"
version = "0.2.88"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283"
checksum = "c5353b8dab669f5e10f5bd76df26a9360c748f054f862ff5f3f8aae0c7fb3907"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.40",
"syn 2.0.39",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.89"
version = "0.2.88"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ab9b36309365056cd639da3134bf87fa8f3d86008abf99e612384a6eecd459f"
checksum = "0d046c5d029ba91a1ed14da14dca44b68bf2f124cfbaf741c54151fdb3e0750b"
[[package]]
name = "wasm-bindgen-test"
version = "0.3.39"
version = "0.3.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2cf9242c0d27999b831eae4767b2a146feb0b27d332d553e605864acd2afd403"
checksum = "c6433b7c56db97397842c46b67e11873eda263170afeb3a2dc74a7cb370fee0d"
dependencies = [
"console_error_panic_hook",
"js-sys",
@@ -3528,13 +3541,13 @@ dependencies = [
[[package]]
name = "wasm-bindgen-test-macro"
version = "0.3.39"
version = "0.3.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "794645f5408c9a039fd09f4d113cdfb2e7eba5ff1956b07bcf701cf4b394fe89"
checksum = "493fcbab756bb764fa37e6bee8cec2dd709eb4273d06d0c282a5e74275ded735"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.40",
"syn 2.0.39",
]
[[package]]
@@ -3631,15 +3644,6 @@ dependencies = [
"windows-targets 0.48.5",
]
[[package]]
name = "windows-sys"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
dependencies = [
"windows-targets 0.52.0",
]
[[package]]
name = "windows-targets"
version = "0.42.2"
@@ -3670,21 +3674,6 @@ dependencies = [
"windows_x86_64_msvc 0.48.5",
]
[[package]]
name = "windows-targets"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd"
dependencies = [
"windows_aarch64_gnullvm 0.52.0",
"windows_aarch64_msvc 0.52.0",
"windows_i686_gnu 0.52.0",
"windows_i686_msvc 0.52.0",
"windows_x86_64_gnu 0.52.0",
"windows_x86_64_gnullvm 0.52.0",
"windows_x86_64_msvc 0.52.0",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.42.2"
@@ -3697,12 +3686,6 @@ version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea"
[[package]]
name = "windows_aarch64_msvc"
version = "0.42.2"
@@ -3715,12 +3698,6 @@ version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
[[package]]
name = "windows_aarch64_msvc"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef"
[[package]]
name = "windows_i686_gnu"
version = "0.42.2"
@@ -3733,12 +3710,6 @@ version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
[[package]]
name = "windows_i686_gnu"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313"
[[package]]
name = "windows_i686_msvc"
version = "0.42.2"
@@ -3751,12 +3722,6 @@ version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
[[package]]
name = "windows_i686_msvc"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a"
[[package]]
name = "windows_x86_64_gnu"
version = "0.42.2"
@@ -3769,12 +3734,6 @@ version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
[[package]]
name = "windows_x86_64_gnu"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.42.2"
@@ -3787,12 +3746,6 @@ version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e"
[[package]]
name = "windows_x86_64_msvc"
version = "0.42.2"
@@ -3805,12 +3758,6 @@ version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
[[package]]
name = "windows_x86_64_msvc"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04"
[[package]]
name = "winnow"
version = "0.5.15"
@@ -3849,23 +3796,3 @@ checksum = "fe5c30ade05e61656247b2e334a031dfd0cc466fadef865bdcdea8d537951bf1"
dependencies = [
"winapi",
]
[[package]]
name = "zerocopy"
version = "0.7.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "306dca4455518f1f31635ec308b6b3e4eb1b11758cefafc782827d0aa7acb5c7"
dependencies = [
"zerocopy-derive",
]
[[package]]
name = "zerocopy-derive"
version = "0.7.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be912bf68235a88fbefd1b73415cb218405958d1655b2ece9035a19920bdf6ba"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.40",
]

View File

@@ -12,29 +12,29 @@ authors = ["Charlie Marsh <charlie.r.marsh@gmail.com>"]
license = "MIT"
[workspace.dependencies]
anyhow = { version = "1.0.76" }
anyhow = { version = "1.0.69" }
bitflags = { version = "2.4.1" }
chrono = { version = "0.4.31", default-features = false, features = ["clock"] }
clap = { version = "4.4.7", features = ["derive"] }
colored = { version = "2.1.0" }
filetime = { version = "0.2.23" }
colored = { version = "2.0.0" }
filetime = { version = "0.2.20" }
glob = { version = "0.3.1" }
globset = { version = "0.4.14" }
ignore = { version = "0.4.21" }
ignore = { version = "0.4.20" }
insta = { version = "1.34.0", feature = ["filters", "glob"] }
is-macro = { version = "0.3.1" }
is-macro = { version = "0.3.0" }
itertools = { version = "0.11.0" }
libcst = { version = "1.1.0", default-features = false }
log = { version = "0.4.17" }
memchr = { version = "2.6.4" }
once_cell = { version = "1.19.0" }
once_cell = { version = "1.17.1" }
path-absolutize = { version = "3.1.1" }
proc-macro2 = { version = "1.0.71" }
proc-macro2 = { version = "1.0.70" }
quote = { version = "1.0.23" }
regex = { version = "1.10.2" }
rustc-hash = { version = "1.1.0" }
schemars = { version = "0.8.16" }
serde = { version = "1.0.193", features = ["derive"] }
schemars = { version = "0.8.15" }
serde = { version = "1.0.190", features = ["derive"] }
serde_json = { version = "1.0.108" }
shellexpand = { version = "3.0.0" }
similar = { version = "2.3.0", features = ["inline"] }
@@ -42,15 +42,15 @@ smallvec = { version = "1.11.2" }
static_assertions = "1.1.0"
strum = { version = "0.25.0", features = ["strum_macros"] }
strum_macros = { version = "0.25.3" }
syn = { version = "2.0.40" }
test-case = { version = "3.3.1" }
thiserror = { version = "1.0.51" }
toml = { version = "0.8.8" }
syn = { version = "2.0.39" }
test-case = { version = "3.2.1" }
thiserror = { version = "1.0.50" }
toml = { version = "0.7.8" }
tracing = { version = "0.1.40" }
tracing-indicatif = { version = "0.3.6" }
tracing-indicatif = { version = "0.3.4" }
tracing-subscriber = { version = "0.3.18", features = ["env-filter"] }
unicode-ident = { version = "1.0.12" }
unicode_names2 = { version = "1.2.1" }
unicode_names2 = { version = "1.2.0" }
unicode-width = { version = "0.1.11" }
uuid = { version = "1.6.1", features = ["v4", "fast-rng", "macro-diagnostics", "js"] }
wsl = { version = "0.1.0" }
@@ -88,20 +88,7 @@ rc_mutex = "warn"
rest_pat_in_fully_bound_structs = "warn"
[profile.release]
# Note that we set these explicitly, and these values
# were chosen based on a trade-off between compile times
# and runtime performance[1].
#
# [1]: https://github.com/astral-sh/ruff/pull/9031
lto = "thin"
codegen-units = 16
# Some crates don't change as much but benefit more from
# more expensive optimization passes, so we selectively
# decrease codegen-units in some cases.
[profile.release.package.ruff_python_parser]
codegen-units = 1
[profile.release.package.ruff_python_ast]
lto = "fat"
codegen-units = 1
[profile.dev.package.insta]
@@ -115,8 +102,8 @@ opt-level = 3
[profile.dev.package.ruff_python_parser]
opt-level = 1
# Use the `--profile profiling` flag to show symbols in release mode.
# e.g. `cargo build --profile profiling`
[profile.profiling]
# Use the `--profile release-debug` flag to show symbols in release mode.
# e.g. `cargo build --profile release-debug`
[profile.release-debug]
inherits = "release"
debug = 1

View File

@@ -150,7 +150,7 @@ Ruff can also be used as a [pre-commit](https://pre-commit.com/) hook via [`ruff
```yaml
- repo: https://github.com/astral-sh/ruff-pre-commit
# Ruff version.
rev: v0.1.9
rev: v0.1.6
hooks:
# Run the linter.
- id: ruff
@@ -194,25 +194,20 @@ exclude = [
".git",
".git-rewrite",
".hg",
".ipynb_checkpoints",
".mypy_cache",
".nox",
".pants.d",
".pyenv",
".pytest_cache",
".pytype",
".ruff_cache",
".svn",
".tox",
".venv",
".vscode",
"__pypackages__",
"_build",
"buck-out",
"build",
"dist",
"node_modules",
"site-packages",
"venv",
]

View File

@@ -1,6 +1,6 @@
[package]
name = "flake8-to-ruff"
version = "0.1.9"
version = "0.1.6"
description = """
Convert Flake8 configuration files to Ruff configuration files.
"""
@@ -23,7 +23,7 @@ configparser = { version = "3.0.3" }
itertools = { workspace = true }
log = { workspace = true }
once_cell = { workspace = true }
pep440_rs = { version = "0.4.0", features = ["serde"] }
pep440_rs = { version = "0.3.12", features = ["serde"] }
regex = { workspace = true }
rustc-hash = { workspace = true }
serde = { workspace = true }

View File

@@ -34,8 +34,8 @@ harness = false
once_cell.workspace = true
serde.workspace = true
serde_json.workspace = true
url = "2.5.0"
ureq = "2.9.1"
url = "2.3.1"
ureq = "2.8.0"
criterion = { version = "0.5.1", default-features = false }
codspeed-criterion-compat = { version="2.3.3", default-features = false, optional = true}

View File

@@ -4,7 +4,7 @@ use ruff_benchmark::criterion::{
criterion_group, criterion_main, BenchmarkId, Criterion, Throughput,
};
use ruff_benchmark::{TestCase, TestFile, TestFileDownloadError};
use ruff_python_formatter::{format_module_ast, PreviewMode, PyFormatOptions};
use ruff_python_formatter::{format_module_ast, PyFormatOptions};
use ruff_python_index::CommentRangesBuilder;
use ruff_python_parser::lexer::lex;
use ruff_python_parser::{parse_tokens, Mode};
@@ -69,8 +69,7 @@ fn benchmark_formatter(criterion: &mut Criterion) {
.expect("Input to be a valid python program");
b.iter(|| {
let options = PyFormatOptions::from_extension(Path::new(case.name()))
.with_preview(PreviewMode::Enabled);
let options = PyFormatOptions::from_extension(Path::new(case.name()));
let formatted =
format_module_ast(&module, &comment_ranges, case.code(), options)
.expect("Formatting to succeed");

View File

@@ -2,7 +2,7 @@ use ruff_benchmark::criterion::{
criterion_group, criterion_main, BenchmarkGroup, BenchmarkId, Criterion, Throughput,
};
use ruff_benchmark::{TestCase, TestFile, TestFileDownloadError};
use ruff_linter::linter::{lint_only, ParseSource};
use ruff_linter::linter::lint_only;
use ruff_linter::rule_selector::PreviewOptions;
use ruff_linter::settings::rule_table::RuleTable;
use ruff_linter::settings::types::PreviewMode;
@@ -10,7 +10,6 @@ use ruff_linter::settings::{flags, LinterSettings};
use ruff_linter::source_kind::SourceKind;
use ruff_linter::{registry::Rule, RuleSelector};
use ruff_python_ast::PySourceType;
use ruff_python_parser::{lexer, parse_program_tokens, Mode};
#[cfg(target_os = "windows")]
#[global_allocator]
@@ -54,13 +53,7 @@ fn benchmark_linter(mut group: BenchmarkGroup, settings: &LinterSettings) {
BenchmarkId::from_parameter(case.name()),
&case,
|b, case| {
// Tokenize the source.
let tokens = lexer::lex(case.code(), Mode::Module).collect::<Vec<_>>();
// Parse the source.
let ast =
parse_program_tokens(tokens.clone(), case.code(), case.name(), false).unwrap();
let kind = SourceKind::Python(case.code().to_string());
b.iter(|| {
let path = case.path();
let result = lint_only(
@@ -68,12 +61,8 @@ fn benchmark_linter(mut group: BenchmarkGroup, settings: &LinterSettings) {
None,
settings,
flags::Noqa::Enabled,
&SourceKind::Python(case.code().to_string()),
&kind,
PySourceType::from(path.as_path()),
ParseSource::Precomputed {
tokens: &tokens,
ast: &ast,
},
);
// Assert that file contains no parse errors

View File

@@ -1,6 +1,6 @@
[package]
name = "ruff_cli"
version = "0.1.9"
version = "0.1.6"
publish = false
authors = { workspace = true }
edition = { workspace = true }
@@ -33,7 +33,7 @@ anyhow = { workspace = true }
argfile = { version = "0.1.6" }
bincode = { version = "1.3.3" }
bitflags = { workspace = true }
cachedir = { version = "0.3.1" }
cachedir = { version = "0.3.0" }
chrono = { workspace = true }
clap = { workspace = true, features = ["derive", "env"] }
clap_complete_command = { version = "0.5.1" }
@@ -69,7 +69,7 @@ insta = { workspace = true, features = ["filters", "json"] }
insta-cmd = { version = "0.4.0" }
tempfile = "3.8.1"
test-case = { workspace = true }
ureq = { version = "2.9.1", features = [] }
ureq = { version = "2.8.0", features = [] }
[target.'cfg(target_os = "windows")'.dependencies]
mimalloc = "0.1.39"

View File

@@ -515,7 +515,7 @@ impl<'a> FormatResults<'a> {
if changed > 0 && unchanged > 0 {
writeln!(
f,
"{} file{} {}, {} file{} {}",
"{} file{} {}, {} file{} left unchanged",
changed,
if changed == 1 { "" } else { "s" },
match self.mode {
@@ -524,10 +524,6 @@ impl<'a> FormatResults<'a> {
},
unchanged,
if unchanged == 1 { "" } else { "s" },
match self.mode {
FormatMode::Write => "left unchanged",
FormatMode::Check | FormatMode::Diff => "already formatted",
},
)
} else if changed > 0 {
writeln!(
@@ -543,13 +539,9 @@ impl<'a> FormatResults<'a> {
} else if unchanged > 0 {
writeln!(
f,
"{} file{} {}",
"{} file{} left unchanged",
unchanged,
if unchanged == 1 { "" } else { "s" },
match self.mode {
FormatMode::Write => "left unchanged",
FormatMode::Check | FormatMode::Diff => "already formatted",
},
)
} else {
Ok(())

View File

@@ -12,7 +12,7 @@ use rustc_hash::FxHashMap;
use crate::cache::{Cache, FileCacheKey, LintCacheData};
use ruff_diagnostics::Diagnostic;
use ruff_linter::linter::{lint_fix, lint_only, FixTable, FixerResult, LinterResult, ParseSource};
use ruff_linter::linter::{lint_fix, lint_only, FixTable, FixerResult, LinterResult};
use ruff_linter::logging::DisplayParseError;
use ruff_linter::message::Message;
use ruff_linter::pyproject_toml::lint_pyproject_toml;
@@ -303,28 +303,12 @@ pub(crate) fn lint_path(
(result, fixed)
} else {
// If we fail to fix, lint the original source code.
let result = lint_only(
path,
package,
settings,
noqa,
&source_kind,
source_type,
ParseSource::None,
);
let result = lint_only(path, package, settings, noqa, &source_kind, source_type);
let fixed = FxHashMap::default();
(result, fixed)
}
} else {
let result = lint_only(
path,
package,
settings,
noqa,
&source_kind,
source_type,
ParseSource::None,
);
let result = lint_only(path, package, settings, noqa, &source_kind, source_type);
let fixed = FxHashMap::default();
(result, fixed)
};
@@ -460,7 +444,6 @@ pub(crate) fn lint_stdin(
noqa,
&source_kind,
source_type,
ParseSource::None,
);
let fixed = FxHashMap::default();
@@ -479,7 +462,6 @@ pub(crate) fn lint_stdin(
noqa,
&source_kind,
source_type,
ParseSource::None,
);
let fixed = FxHashMap::default();
(result, fixed)

View File

@@ -13,7 +13,7 @@ use ruff_linter::fs::relativize_path;
use ruff_linter::logging::LogLevel;
use ruff_linter::message::{
AzureEmitter, Emitter, EmitterContext, GithubEmitter, GitlabEmitter, GroupedEmitter,
JsonEmitter, JsonLinesEmitter, JunitEmitter, PylintEmitter, SarifEmitter, TextEmitter,
JsonEmitter, JsonLinesEmitter, JunitEmitter, PylintEmitter, TextEmitter,
};
use ruff_linter::notify_user;
use ruff_linter::registry::{AsRule, Rule};
@@ -125,7 +125,15 @@ impl Printer {
if let Some(fixables) = fixables {
let fix_prefix = format!("[{}]", "*".cyan());
if self.unsafe_fixes.is_hint() {
if self.unsafe_fixes.is_enabled() {
if fixables.applicable > 0 {
writeln!(
writer,
"{fix_prefix} {} fixable with the --fix option.",
fixables.applicable
)?;
}
} else {
if fixables.applicable > 0 && fixables.unapplicable_unsafe > 0 {
let es = if fixables.unapplicable_unsafe == 1 {
""
@@ -155,14 +163,6 @@ impl Printer {
fixables.unapplicable_unsafe
)?;
}
} else {
if fixables.applicable > 0 {
writeln!(
writer,
"{fix_prefix} {} fixable with the --fix option.",
fixables.applicable
)?;
}
}
}
} else {
@@ -291,9 +291,6 @@ impl Printer {
SerializationFormat::Azure => {
AzureEmitter.emit(writer, &diagnostics.messages, &context)?;
}
SerializationFormat::Sarif => {
SarifEmitter.emit(writer, &diagnostics.messages, &context)?;
}
}
writer.flush()?;

View File

@@ -139,99 +139,6 @@ if condition:
Ok(())
}
#[test]
fn docstring_options() -> Result<()> {
let tempdir = TempDir::new()?;
let ruff_toml = tempdir.path().join("ruff.toml");
fs::write(
&ruff_toml,
r#"
[format]
docstring-code-format = true
docstring-code-line-length = 20
"#,
)?;
assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
.args(["format", "--config"])
.arg(&ruff_toml)
.arg("-")
.pass_stdin(r#"
def f(x):
'''
Something about `f`. And an example:
.. code-block:: python
foo, bar, quux = this_is_a_long_line(lion, hippo, lemur, bear)
Another example:
```py
foo, bar, quux = this_is_a_long_line(lion, hippo, lemur, bear)
```
And another:
>>> foo, bar, quux = this_is_a_long_line(lion, hippo, lemur, bear)
'''
pass
"#), @r###"
success: true
exit_code: 0
----- stdout -----
def f(x):
"""
Something about `f`. And an example:
.. code-block:: python
(
foo,
bar,
quux,
) = this_is_a_long_line(
lion,
hippo,
lemur,
bear,
)
Another example:
```py
(
foo,
bar,
quux,
) = this_is_a_long_line(
lion,
hippo,
lemur,
bear,
)
```
And another:
>>> (
... foo,
... bar,
... quux,
... ) = this_is_a_long_line(
... lion,
... hippo,
... lemur,
... bear,
... )
"""
pass
----- stderr -----
"###);
Ok(())
}
#[test]
fn mixed_line_endings() -> Result<()> {
let tempdir = TempDir::new()?;
@@ -255,7 +162,7 @@ fn mixed_line_endings() -> Result<()> {
----- stdout -----
----- stderr -----
2 files already formatted
2 files left unchanged
"###);
Ok(())
}
@@ -328,60 +235,6 @@ OTHER = "OTHER"
Ok(())
}
#[test]
fn messages() -> Result<()> {
let tempdir = TempDir::new()?;
fs::write(
tempdir.path().join("main.py"),
r#"
from test import say_hy
if __name__ == "__main__":
say_hy("dear Ruff contributor")
"#,
)?;
assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
.current_dir(tempdir.path())
.args(["format", "--no-cache", "--isolated", "--check"])
.arg("main.py"), @r###"
success: false
exit_code: 1
----- stdout -----
Would reformat: main.py
1 file would be reformatted
----- stderr -----
"###);
assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
.current_dir(tempdir.path())
.args(["format", "--no-cache", "--isolated"])
.arg("main.py"), @r###"
success: true
exit_code: 0
----- stdout -----
1 file reformatted
----- stderr -----
"###);
assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
.current_dir(tempdir.path())
.args(["format", "--no-cache", "--isolated"])
.arg("main.py"), @r###"
success: true
exit_code: 0
----- stdout -----
1 file left unchanged
----- stderr -----
"###);
Ok(())
}
#[test]
fn force_exclude() -> Result<()> {
let tempdir = TempDir::new()?;
@@ -930,7 +783,7 @@ fn test_diff() {
----- stderr -----
2 files would be reformatted, 1 file already formatted
2 files would be reformatted, 1 file left unchanged
"###);
});
}

View File

@@ -1158,44 +1158,6 @@ fn check_hints_hidden_unsafe_fixes_with_no_safe_fixes() {
"###);
}
#[test]
fn check_no_hint_for_hidden_unsafe_fixes_when_disabled() {
let mut cmd = RuffCheck::default()
.args(["--select", "F601,UP034", "--no-unsafe-fixes"])
.build();
assert_cmd_snapshot!(cmd
.pass_stdin("x = {'a': 1, 'a': 1}\nprint(('foo'))\n"),
@r###"
success: false
exit_code: 1
----- stdout -----
-:1:14: F601 Dictionary key literal `'a'` repeated
-:2:7: UP034 [*] Avoid extraneous parentheses
Found 2 errors.
[*] 1 fixable with the --fix option.
----- stderr -----
"###);
}
#[test]
fn check_no_hint_for_hidden_unsafe_fixes_with_no_safe_fixes_when_disabled() {
let mut cmd = RuffCheck::default()
.args(["--select", "F601", "--no-unsafe-fixes"])
.build();
assert_cmd_snapshot!(cmd
.pass_stdin("x = {'a': 1, 'a': 1}\n"),
@r###"
success: false
exit_code: 1
----- stdout -----
-:1:14: F601 Dictionary key literal `'a'` repeated
Found 1 error.
----- stderr -----
"###);
}
#[test]
fn check_shows_unsafe_fixes_with_opt_in() {
let mut cmd = RuffCheck::default()

View File

@@ -7,7 +7,7 @@ use ruff_text_size::{Ranged, TextRange, TextSize};
/// A text edit to be applied to a source file. Inserts, deletes, or replaces
/// content at a given location.
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
#[derive(Clone, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Edit {
/// The start location of the edit.

View File

@@ -1,6 +1,6 @@
[package]
name = "ruff_linter"
version = "0.1.9"
version = "0.1.6"
publish = false
authors = { workspace = true }
edition = { workspace = true }
@@ -52,7 +52,7 @@ path-absolutize = { workspace = true, features = [
"use_unix_paths_on_wasm",
] }
pathdiff = { version = "0.2.1" }
pep440_rs = { version = "0.4.0", features = ["serde"] }
pep440_rs = { version = "0.3.12", features = ["serde"] }
pyproject-toml = { version = "0.8.1" }
quick-junit = { version = "0.3.5" }
regex = { workspace = true }
@@ -71,7 +71,6 @@ toml = { workspace = true }
typed-arena = { version = "2.0.2" }
unicode-width = { workspace = true }
unicode_names2 = { workspace = true }
url = { version = "2.2.2" }
wsl = { version = "0.1.0" }
[dev-dependencies]

View File

@@ -39,18 +39,3 @@ def func():
for i in range(1110):
if True:
break
# TODO(charlie): The `pass` here does not get properly redirected to the top of the
# loop, unlike below.
def func():
for i in range(5):
pass
else:
return 1
def func():
for i in range(5):
pass
else:
return 1
x = 1

View File

@@ -129,11 +129,3 @@ def func():
print("Grass is green")
case Color.BLUE:
print("I'm feeling the blues :(")
def func(point):
match point:
case (0, 0):
print("Origin")
case foo:
raise ValueError("oops")

View File

@@ -63,169 +63,3 @@ def func(x: int):
return "str"
else:
return None
def func(x: int):
if x:
return 1
def func():
x = 1
def func(x: int):
if x > 0:
return 1
def func(x: int):
match x:
case [1, 2, 3]:
return 1
case 4 as y:
return "foo"
def func(x: int):
for i in range(5):
if i > 0:
return 1
def func(x: int):
for i in range(5):
if i > 0:
return 1
else:
return 4
def func(x: int):
for i in range(5):
if i > 0:
break
else:
return 4
def func(x: int):
try:
pass
except:
return 1
def func(x: int):
try:
pass
except:
return 1
finally:
return 2
def func(x: int):
try:
pass
except:
return 1
else:
return 2
def func(x: int):
try:
return 1
except:
return 2
else:
pass
def func(x: int):
while x > 0:
break
return 1
import abc
from abc import abstractmethod
class Foo(abc.ABC):
@abstractmethod
def method(self):
pass
@abc.abstractmethod
def method(self):
"""Docstring."""
@abc.abstractmethod
def method(self):
...
@staticmethod
@abstractmethod
def method():
pass
@classmethod
@abstractmethod
def method(cls):
pass
@abstractmethod
def method(self):
if self.x > 0:
return 1
else:
return 1.5
def func(x: int):
try:
pass
except:
return 2
def func(x: int):
try:
pass
except:
return 2
else:
return 3
def func(x: int):
if not x:
raise ValueError
else:
raise TypeError
def func(x: int):
if not x:
raise ValueError
else:
return 1
from typing import overload
@overload
def overloaded(i: int) -> "int":
...
@overload
def overloaded(i: "str") -> "str":
...
def overloaded(i):
return i

View File

@@ -8,7 +8,6 @@ def func(address):
# Error
"0.0.0.0"
'0.0.0.0'
f"0.0.0.0"
# Error

View File

@@ -5,9 +5,6 @@ with open("/abc/tmp", "w") as f:
with open("/tmp/abc", "w") as f:
f.write("def")
with open(f"/tmp/abc", "w") as f:
f.write("def")
with open("/var/tmp/123", "w") as f:
f.write("def")

View File

@@ -127,21 +127,3 @@ class MultipleConsecutiveFields(models.Model):
pass
middle_name = models.CharField(max_length=32)
class BaseModel(models.Model):
pass
class StrBeforeFieldInheritedModel(BaseModel):
"""Model with `__str__` before fields."""
class Meta:
verbose_name = "test"
verbose_name_plural = "tests"
def __str__(self):
return "foobar"
first_name = models.CharField(max_length=32)

View File

@@ -27,7 +27,7 @@ def f_ok():
raise RuntimeError(msg)
def f_msg_defined():
def f_unfixable():
msg = "hello"
raise RuntimeError("This is an example exception")

View File

@@ -10,6 +10,7 @@ Foo.objects.create(**{**bar}) # PIE804
foo(**{})
foo(**{**data, "foo": "buzz"})
foo(**buzz)
foo(**{"bar-foo": True})
@@ -19,8 +20,3 @@ foo(**{buzz: True})
foo(**{"": True})
foo(**{f"buzz__{bar}": True})
abc(**{"for": 3})
foo(**{},)
# Duplicated key names won't be fixed, to avoid syntax errors.
abc(**{'a': b}, **{'a': c}) # PIE804
abc(a=1, **{'a': c}, **{'b': c}) # PIE804

View File

@@ -1,13 +1,8 @@
import typing
import typing_extensions
from typing import TypeVar
from typing_extensions import ParamSpec, TypeVarTuple
_T = typing.TypeVar("_T")
_Ts = typing_extensions.TypeVarTuple("_Ts")
_P = ParamSpec("_P")
_P2 = typing.ParamSpec("_P2")
_Ts2 = TypeVarTuple("_Ts2")
_P = TypeVar("_P")
# OK
_UsedTypeVar = TypeVar("_UsedTypeVar")

View File

@@ -1,13 +1,8 @@
import typing
import typing_extensions
from typing import TypeVar
from typing_extensions import ParamSpec, TypeVarTuple
_T = typing.TypeVar("_T")
_Ts = typing_extensions.TypeVarTuple("_Ts")
_P = ParamSpec("_P")
_P2 = typing.ParamSpec("_P2")
_Ts2 = TypeVarTuple("_Ts2")
_P = TypeVar("_P")
# OK
_UsedTypeVar = TypeVar("_UsedTypeVar")

View File

@@ -22,7 +22,3 @@ Snake_case_alias: TypeAlias = int | float # PYI042, since not camel case
# check that this edge case doesn't crash
_: TypeAlias = str | int
# PEP 695
type foo_bar = int | str
type FooBar = int | str

View File

@@ -22,7 +22,3 @@ Snake_case_alias: TypeAlias = int | float # PYI042, since not camel case
# check that this edge case doesn't crash
_: TypeAlias = str | int
# PEP 695
type foo_bar = int | str
type FooBar = int | str

View File

@@ -21,7 +21,3 @@ _PrivateAliasS2: TypeAlias = Annotated[str, "also okay"]
# check that this edge case doesn't crash
_: TypeAlias = str | int
# PEP 695
type _FooT = str | int
type Foo = str | int

View File

@@ -21,7 +21,3 @@ _PrivateAliasS2: TypeAlias = Annotated[str, "also okay"]
# check that this edge case doesn't crash
_: TypeAlias = str | int
# PEP 695
type _FooT = str | int
type Foo = str | int

View File

@@ -10,14 +10,3 @@ def foo_no_return_typing_extensions(
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): ...
def foo_args(*args: NoReturn): ... # Error: PYI050
def foo_kwargs(**kwargs: NoReturn): ... # Error: PYI050
def foo_args_kwargs(*args: NoReturn, **kwargs: NoReturn): ... # Error: PYI050
def foo_int_args(*args: int): ...
def foo_int_kwargs(**kwargs: int): ...
def foo_int_args_kwargs(*args: int, **kwargs: int): ...
def foo_int_args_no_return(*args: int, **kwargs: NoReturn): ... # Error: PYI050
def foo_int_kwargs_no_return(*args: NoReturn, **kwargs: int): ... # Error: PYI050
def foo_args_never(*args: Never): ...
def foo_kwargs_never(**kwargs: Never): ...
def foo_args_kwargs_never(*args: Never, **kwargs: Never): ...

View File

@@ -32,7 +32,6 @@ def f8(x: bytes = b"50 character byte stringgggggggggggggggggggggggggg\xff") ->
foo: str = "50 character stringggggggggggggggggggggggggggggggg"
bar: str = "51 character stringgggggggggggggggggggggggggggggggg"
baz: str = f"51 character stringgggggggggggggggggggggggggggggggg"
baz: bytes = b"50 character byte stringgggggggggggggggggggggggggg"

View File

@@ -29,10 +29,6 @@ baz: bytes = b"50 character byte stringgggggggggggggggggggggggggg" # OK
qux: bytes = b"51 character byte stringggggggggggggggggggggggggggg\xff" # Error: PYI053
ffoo: str = f"50 character stringggggggggggggggggggggggggggggggg" # OK
fbar: str = f"51 character stringgggggggggggggggggggggggggggggggg" # Error: PYI053
class Demo:
"""Docstrings are excluded from this rule. Some padding.""" # OK

View File

@@ -37,28 +37,3 @@ def func():
# PYI055
x: Union[type[requests_mock.Mocker], type[httpretty], type[str]] = requests_mock.Mocker
def convert_union(union: UnionType) -> _T | None:
converters: tuple[
type[_T] | type[Converter[_T]] | Converter[_T] | Callable[[str], _T], ... # PYI055
] = union.__args__
...
def convert_union(union: UnionType) -> _T | None:
converters: tuple[
Union[type[_T] | type[Converter[_T]] | Converter[_T] | Callable[[str], _T]], ... # PYI055
] = union.__args__
...
def convert_union(union: UnionType) -> _T | None:
converters: tuple[
Union[type[_T] | type[Converter[_T]]] | Converter[_T] | Callable[[str], _T], ... # PYI055
] = union.__args__
...
def convert_union(union: UnionType) -> _T | None:
converters: tuple[
Union[type[_T] | type[Converter[_T]] | str] | Converter[_T] | Callable[[str], _T], ... # PYI055
] = union.__args__
...

View File

@@ -82,14 +82,3 @@ raise IndexError();
# RSE102
raise Foo()
# OK
raise ctypes.WinError()
def func():
pass
# OK
raise func()

View File

@@ -1,5 +1,6 @@
# Errors
"yoda" == compare # SIM300
"yoda" == compare # SIM300
42 == age # SIM300
("a", "b") == compare # SIM300
"yoda" <= compare # SIM300
@@ -12,17 +13,10 @@ YODA > age # SIM300
YODA >= age # SIM300
JediOrder.YODA == age # SIM300
0 < (number - 100) # SIM300
SomeClass().settings.SOME_CONSTANT_VALUE > (60 * 60) # SIM300
B<A[0][0]or B
B or(B)<A[0][0]
# Errors in preview
['upper'] == UPPER_LIST
{} == DummyHandler.CONFIG
# Errors in stable
UPPER_LIST == ['upper']
DummyHandler.CONFIG == {}
# OK
compare == "yoda"
age == 42
@@ -37,6 +31,3 @@ age <= YODA
YODA == YODA
age == JediOrder.YODA
(number - 100) > 0
SECONDS_IN_DAY == 60 * 60 * 24 # Error in 0.1.8
SomeClass().settings.SOME_CONSTANT_VALUE > (60 * 60) # Error in 0.1.8
{"non-empty-dict": "is-ok"} == DummyHandler.CONFIG

View File

@@ -19,32 +19,8 @@ async def func():
bar = "bar"
trio.sleep(bar)
x, y = 0, 2000
trio.sleep(x) # TRIO115
trio.sleep(y) # OK
(a, b, [c, (d, e)]) = (1, 2, (0, [4, 0]))
trio.sleep(c) # TRIO115
trio.sleep(d) # OK
trio.sleep(e) # TRIO115
m_x, m_y = 0
trio.sleep(m_y) # OK
trio.sleep(m_x) # OK
m_a = m_b = 0
trio.sleep(m_a) # TRIO115
trio.sleep(m_b) # TRIO115
m_c = (m_d, m_e) = (0, 0)
trio.sleep(m_c) # OK
trio.sleep(m_d) # TRIO115
trio.sleep(m_e) # TRIO115
def func():
import trio
trio.run(trio.sleep(0)) # TRIO115
@@ -57,10 +33,3 @@ def func():
async def func():
await sleep(seconds=0) # TRIO115
def func():
import trio
if (walrus := 0) == 0:
trio.sleep(walrus) # TRIO115

View File

@@ -1,18 +0,0 @@
from __future__ import annotations
from typing import TypeVar
x: "int" | str # TCH006
x: ("int" | str) | "bool" # TCH006
def func():
x: "int" | str # OK
z: list[str, str | "int"] = [] # TCH006
type A = Value["int" | str] # OK
OldS = TypeVar('OldS', int | 'str', str) # TCH006

View File

@@ -1,16 +0,0 @@
from typing import TypeVar
x: "int" | str # TCH006
x: ("int" | str) | "bool" # TCH006
def func():
x: "int" | str # OK
z: list[str, str | "int"] = [] # TCH006
type A = Value["int" | str] # OK
OldS = TypeVar('OldS', int | 'str', str) # TCH006

View File

@@ -1,7 +0,0 @@
"""Add `TYPE_CHECKING` to an existing `typing` import. Another member is moved."""
from __future__ import annotations
from typing import Final
Const: Final[dict] = {}

View File

@@ -1,7 +0,0 @@
"""Using `TYPE_CHECKING` from an existing `typing` import. Another member is moved."""
from __future__ import annotations
from typing import Final, TYPE_CHECKING
Const: Final[dict] = {}

View File

@@ -1,7 +0,0 @@
"""Using `TYPE_CHECKING` from an existing `typing` import. Another member is moved."""
from __future__ import annotations
from typing import Final, Mapping
Const: Final[dict] = {}

View File

@@ -1,92 +0,0 @@
def f():
from pandas import DataFrame
def baz() -> DataFrame:
...
def f():
from pandas import DataFrame
def baz() -> DataFrame[int]:
...
def f():
from pandas import DataFrame
def baz() -> DataFrame["int"]:
...
def f():
import pandas as pd
def baz() -> pd.DataFrame:
...
def f():
import pandas as pd
def baz() -> pd.DataFrame.Extra:
...
def f():
import pandas as pd
def baz() -> pd.DataFrame | int:
...
def f():
from pandas import DataFrame
def baz() -> DataFrame():
...
def f():
from typing import Literal
from pandas import DataFrame
def baz() -> DataFrame[Literal["int"]]:
...
def f():
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from pandas import DataFrame
def func(value: DataFrame):
...
def f():
from pandas import DataFrame, Series
def baz() -> DataFrame | Series:
...
def f():
from pandas import DataFrame, Series
def baz() -> (
DataFrame |
Series
):
...
class C:
x: DataFrame[
int
] = 1
def func() -> DataFrame[[DataFrame[_P, _R]], DataFrame[_P, _R]]:
...

View File

@@ -1,2 +0,0 @@
import __future__
from __future__ import annotations

View File

@@ -1,4 +0,0 @@
from a import x
import b
from c import y
import d

View File

@@ -1,2 +0,0 @@
import __future__
from __future__ import annotations

View File

@@ -52,9 +52,3 @@ def model_assign() -> None:
Bad = import_string("django.core.exceptions.ValidationError") # N806
ValidationError = import_string("django.core.exceptions.ValidationError") # OK
Bad = apps.get_model() # N806
Bad = apps.get_model(model_name="Stream") # N806
Address: Type = apps.get_model("zerver", variable) # OK
ValidationError = import_string(variable) # N806

View File

@@ -63,8 +63,3 @@ for i in list(foo_tuple): # Ok
for i in list(foo_set): # Ok
foo_set.append(i + 1)
x, y, nested_tuple = (1, 2, (3, 4, 5))
for i in list(nested_tuple): # PERF101
pass

View File

@@ -72,15 +72,3 @@ a = 42 # (Two spaces)
# EF Means test is giving error and Failing
#! Means test is segfaulting
# 8 Means test runs forever
#: Colon prefix is okay
###This is a variable ###
# We should strip the space, but preserve the hashes.
#: E266:1:3
## Foo
a = 1 ## Foo
a = 1 #:Foo

View File

@@ -60,6 +60,3 @@ def f():
if (a and
b):
pass
#: Okay
def f():
return 1

View File

@@ -19,32 +19,21 @@ if x > 0:
else:
import e
import sys
sys.path.insert(0, "some/path")
__some__magic = 1
import f
import matplotlib
matplotlib.use("Agg")
import g
__some__magic = 1
import h
def foo() -> None:
import i
import e
if __name__ == "__main__":
import j
import g
import k; import l
import h; import i
if __name__ == "__main__":
import m; \
import n
import j; \
import k

View File

@@ -1,9 +0,0 @@
import a
"""Some other docstring."""
import b
"""Some other docstring."""
import c

View File

@@ -43,6 +43,3 @@ regex = '''
''' # noqa
regex = '\\\_'
#: W605:1:7
u'foo\ bar'

View File

@@ -1,54 +1,40 @@
# Same as `W605_0.py` but using f-strings instead.
#: W605:1:10
regex = f'\.png$'
regex = '\.png$'
#: W605:2:1
regex = f'''
regex = '''
\.png$
'''
#: W605:2:6
f(
f'\_'
'\_'
)
#: W605:4:6
f"""
"""
multi-line
literal
with \_ somewhere
in the middle
"""
#: W605:1:38
value = f'new line\nand invalid escape \_ here'
def f():
#: W605:1:11
return'\.png$'
#: Okay
regex = fr'\.png$'
regex = f'\\.png$'
regex = fr'''
regex = r'\.png$'
regex = '\\.png$'
regex = r'''
\.png$
'''
regex = fr'''
regex = r'''
\\.png$
'''
s = f'\\'
regex = f'\w' # noqa
regex = f'''
s = '\\'
regex = '\w' # noqa
regex = '''
\w
''' # noqa
regex = f'\\\_'
value = f'\{{1}}'
value = f'\{1}'
value = f'{1:\}'
value = f"{f"\{1}"}"
value = rf"{f"\{1}"}"
# Okay
value = rf'\{{1}}'
value = rf'\{1}'
value = rf'{1:\}'
value = f"{rf"\{1}"}"

View File

@@ -0,0 +1,54 @@
# Same as `W605_0.py` but using f-strings instead.
#: W605:1:10
regex = f'\.png$'
#: W605:2:1
regex = f'''
\.png$
'''
#: W605:2:6
f(
f'\_'
)
#: W605:4:6
f"""
multi-line
literal
with \_ somewhere
in the middle
"""
#: W605:1:38
value = f'new line\nand invalid escape \_ here'
#: Okay
regex = fr'\.png$'
regex = f'\\.png$'
regex = fr'''
\.png$
'''
regex = fr'''
\\.png$
'''
s = f'\\'
regex = f'\w' # noqa
regex = f'''
\w
''' # noqa
regex = f'\\\_'
value = f'\{{1}}'
value = f'\{1}'
value = f'{1:\}'
value = f"{f"\{1}"}"
value = rf"{f"\{1}"}"
# Okay
value = rf'\{{1}}'
value = rf'\{1}'
value = rf'{1:\}'
value = f"{rf"\{1}"}"

View File

@@ -713,12 +713,5 @@ def retain_extra_whitespace_not_overindented():
This is not overindented
This is overindented, but since one line is not overindented this should not raise
And so is this, but it we should preserve the extra space on this line relative
"""
def inconsistent_indent_byte_size():
"""There's a non-breaking space (2-bytes) after 3 spaces (https://github.com/astral-sh/ruff/issues/9080).
    Returns:
And so is this, but it we should preserve the extra space on this line relative
"""

View File

@@ -1,16 +1,5 @@
"""
Author
"""
class Platform:
""" Remove sampler
Args:
    Returns:
"""
def memory_test():
"""
   参数含义precision:精确到小数点后几位
"""

View File

@@ -1,4 +0,0 @@
import re
from typing import Annotated
type X = Annotated[int, lambda: re.compile("x")]

View File

@@ -1,5 +0,0 @@
"""Docstring"""
"""Non-docstring"""
from __future__ import absolute_import

View File

@@ -1,8 +0,0 @@
"""Test for accessing class members within a generator."""
class Class:
items = []
if len(replacements := {item[1] for item in items}) > 1:
pass

View File

@@ -3,11 +3,6 @@ import subprocess
# Errors.
subprocess.run("ls")
subprocess.run("ls", shell=True)
subprocess.run(
["ls"],
shell=False,
)
subprocess.run(["ls"], **kwargs)
# Non-errors.
subprocess.run("ls", check=True)

View File

@@ -32,16 +32,3 @@ def f(x, y, z, *, u, v, w): # Too many arguments (6/5)
def f(x, y, z, a, b, c, *, u, v, w): # Too many arguments (9/5)
pass
from typing import override, overload
@override
def f(x, y, z, a, b, c, *, u, v, w): # OK
pass
@overload
def f(x, y, z, a, b, c, *, u, v, w): # OK
pass

View File

@@ -1,36 +0,0 @@
def func() -> None: # OK
# 15 is max default
first = 1
second = 2
third = 3
fourth = 4
fifth = 5
sixth = 6
seventh = 7
eighth = 8
ninth = 9
tenth = 10
eleventh = 11
twelveth = 12
thirteenth = 13
fourteenth = 14
fifteenth = 15
def func() -> None: # PLR0914
first = 1
second = 2
third = 3
fourth = 4
fifth = 5
sixth = 6
seventh = 7
eighth = 8
ninth = 9
tenth = 10
eleventh = 11
twelfth = 12
thirteenth = 13
fourteenth = 14
fifteenth = 15
sixteenth = 16

View File

@@ -1,30 +0,0 @@
def f(x, y, z, t, u, v, w, r): # Too many positional arguments (8/3)
pass
def f(x): # OK
pass
def f(x, y, z, _t, _u, _v, _w, r): # OK (underscore-prefixed names are ignored
pass
def f(x, y, z, *, u=1, v=1, r=1): # OK
pass
def f(x=1, y=1, z=1): # OK
pass
def f(x, y, z, /, u, v, w): # Too many positional arguments (6/3)
pass
def f(x, y, z, *, u, v, w): # OK
pass
def f(x, y, z, a, b, c, *, u, v, w): # Too many positional arguments (6/3)
pass

View File

@@ -1,10 +0,0 @@
# Too many positional arguments (7/4) for max_positional=4
# OK for dummy_variable_rgx ~ "skip_.*"
def f(w, x, y, z, skip_t, skip_u, skip_v):
pass
# Too many positional arguments (7/4) for max_args=4
# Too many positional arguments (7/3) for dummy_variable_rgx ~ "skip_.*"
def f(w, x, y, z, t, u, v):
pass

View File

@@ -1,40 +0,0 @@
FRUITS = {"apple": 1, "orange": 10, "berry": 22}
def fix_these():
[FRUITS[fruit_name] for fruit_name, fruit_count in FRUITS.items()] # PLR1733
{FRUITS[fruit_name] for fruit_name, fruit_count in FRUITS.items()} # PLR1733
{fruit_name: FRUITS[fruit_name] for fruit_name, fruit_count in FRUITS.items()} # PLR1733
for fruit_name, fruit_count in FRUITS.items():
print(FRUITS[fruit_name]) # PLR1733
blah = FRUITS[fruit_name] # PLR1733
assert FRUITS[fruit_name] == "pear" # PLR1733
def dont_fix_these():
# once there is an assignment to the dict[index], we stop emitting diagnostics
for fruit_name, fruit_count in FRUITS.items():
FRUITS[fruit_name] = 0 # OK
assert FRUITS[fruit_name] == 0 # OK
# once there is an assignment to the key, we stop emitting diagnostics
for fruit_name, fruit_count in FRUITS.items():
fruit_name = 0 # OK
assert FRUITS[fruit_name] == 0 # OK
# once there is an assignment to the value, we stop emitting diagnostics
for fruit_name, fruit_count in FRUITS.items():
if fruit_count < 5:
fruit_count = -fruit_count
assert FRUITS[fruit_name] == 0 # OK
def value_intentionally_unused():
[FRUITS[fruit_name] for fruit_name, _ in FRUITS.items()] # OK
{FRUITS[fruit_name] for fruit_name, _ in FRUITS.items()} # OK
{fruit_name: FRUITS[fruit_name] for fruit_name, _ in FRUITS.items()} # OK
for fruit_name, _ in FRUITS.items():
print(FRUITS[fruit_name]) # OK
blah = FRUITS[fruit_name] # OK
assert FRUITS[fruit_name] == "pear" # OK

View File

@@ -12,7 +12,7 @@ def fix_these():
print(letters[index]) # PLR1736
blah = letters[index] # PLR1736
assert letters[index] == "d" # PLR1736
for index, letter in builtins.enumerate(letters):
print(letters[index]) # PLR1736
blah = letters[index] # PLR1736
@@ -22,43 +22,38 @@ def fix_these():
def dont_fix_these():
# once there is an assignment to the sequence[index], we stop emitting diagnostics
for index, letter in enumerate(letters):
letters[index] = "d" # OK
letters[index] += "e" # OK
assert letters[index] == "de" # OK
letters[index] = "d" # Ok
letters[index] += "e" # Ok
assert letters[index] == "de" # Ok
# once there is an assignment to the index, we stop emitting diagnostics
for index, letter in enumerate(letters):
index += 1 # OK
print(letters[index]) # OK
index += 1 # Ok
print(letters[index]) # Ok
# once there is an assignment to the sequence, we stop emitting diagnostics
for index, letter in enumerate(letters):
letters = ["d", "e", "f"] # OK
print(letters[index]) # OK
# once there is an assignment to the value, we stop emitting diagnostics
for index, letter in enumerate(letters):
letter = "d"
print(letters[index]) # OK
letters = ["d", "e", "f"] # Ok
print(letters[index]) # Ok
# once there is an deletion from or of the sequence or index, we stop emitting diagnostics
for index, letter in enumerate(letters):
del letters[index] # OK
print(letters[index]) # OK
del letters[index] # Ok
print(letters[index]) # Ok
for index, letter in enumerate(letters):
del letters # OK
print(letters[index]) # OK
del letters # Ok
print(letters[index]) # Ok
for index, letter in enumerate(letters):
del index # OK
print(letters[index]) # OK
del index # Ok
print(letters[index]) # Ok
def value_intentionally_unused():
[letters[index] for index, _ in enumerate(letters)] # OK
{letters[index] for index, _ in enumerate(letters)} # OK
{index: letters[index] for index, _ in enumerate(letters)} # OK
[letters[index] for index, _ in enumerate(letters)] # Ok
{letters[index] for index, _ in enumerate(letters)} # Ok
{index: letters[index] for index, _ in enumerate(letters)} # Ok
for index, _ in enumerate(letters):
print(letters[index]) # OK
blah = letters[index] # OK
letters[index] = "d" # OK
print(letters[index]) # Ok
blah = letters[index] # Ok
letters[index] = "d" # Ok

View File

@@ -42,30 +42,3 @@ tempfile.SpooledTemporaryFile(0, "w", encoding="utf-8")
tempfile.SpooledTemporaryFile(0, "w", -1, "utf-8")
tempfile.SpooledTemporaryFile(0, "wb")
tempfile.SpooledTemporaryFile(0, )
open("test.txt",)
open()
open(
"test.txt", # comment
)
open(
"test.txt",
# comment
)
open(("test.txt"),)
open(
("test.txt"), # comment
)
open(
("test.txt"),
# comment
)
open((("test.txt")),)
open(
(("test.txt")), # comment
)
open(
(("test.txt")),
# comment
)

View File

@@ -1,28 +1,30 @@
u"Hello"
# These should change
x = u"Hello"
x = u"Hello" # UP025
u'world'
u'world' # UP025
print(u"Hello")
print(u"Hello") # UP025
print(u'world') # UP025
print(u'world')
import foo
foo(u"Hello", U"world", a=u"Hello", b=u"world") # UP025
foo(u"Hello", U"world", a=u"Hello", b=u"world")
# Retain quotes when fixing.
x = u'hello' # UP025
x = u"""hello""" # UP025
x = u'''hello''' # UP025
x = u'Hello "World"' # UP025
# These should stay quoted they way they are
u = "Hello" # OK
u = u # OK
x = u'hello'
x = u"""hello"""
x = u'''hello'''
x = u'Hello "World"'
# These should not change
u = "Hello"
u = u
def hello():
return"Hello" # OK
return"Hello"
f"foo"u"bar" # OK
f"foo" u"bar" # OK
f"foo"u"bar"
f"foo" u"bar"

View File

@@ -110,10 +110,3 @@ print('Hello %(arg)s' % bar['bop'])
"%s" % (
x, # comment
)
path = "%s-%s-%s.pem" % (
safe_domain_name(cn), # common name, which should be filename safe because it is IDNA-encoded, but in case of a malformed cert make sure it's ok to use as a filename
cert.not_valid_after.date().isoformat().replace("-", ""), # expiration date
hexlify(cert.fingerprint(hashes.SHA256())).decode("ascii")[0:8], # fingerprint prefix
)

View File

@@ -243,12 +243,3 @@ raise ValueError(
).format(a, b)
("{}" "{{{}}}").format(a, b)
# The dictionary should be parenthesized.
"{}".format({0: 1}[0])
# The dictionary should be parenthesized.
"{}".format({0: 1}.bar)
# The dictionary should be parenthesized.
"{}".format({0: 1}())

View File

@@ -1,61 +0,0 @@
# Errors.
op_bitnot = lambda x: ~x
op_not = lambda x: not x
op_pos = lambda x: +x
op_neg = lambda x: -x
op_add = lambda x, y: x + y
op_sub = lambda x, y: x - y
op_mult = lambda x, y: x * y
op_matmutl = lambda x, y: x @ y
op_truediv = lambda x, y: x / y
op_mod = lambda x, y: x % y
op_pow = lambda x, y: x ** y
op_lshift = lambda x, y: x << y
op_rshift = lambda x, y: x >> y
op_bitor = lambda x, y: x | y
op_xor = lambda x, y: x ^ y
op_bitand = lambda x, y: x & y
op_floordiv = lambda x, y: x // y
op_eq = lambda x, y: x == y
op_ne = lambda x, y: x != y
op_lt = lambda x, y: x < y
op_lte = lambda x, y: x <= y
op_gt = lambda x, y: x > y
op_gte = lambda x, y: x >= y
op_is = lambda x, y: x is y
op_isnot = lambda x, y: x is not y
op_in = lambda x, y: y in x
def op_not2(x):
return not x
def op_add2(x, y):
return x + y
class Adder:
def add(x, y):
return x + y
# OK.
op_add3 = lambda x, y = 1: x + y
op_neg2 = lambda x, y: y - x
op_notin = lambda x, y: y not in x
op_and = lambda x, y: y and x
op_or = lambda x, y: y or x
op_in = lambda x, y: x in y
def op_neg3(x, y):
return y - x
def op_add4(x, y = 1):
return x + y
def op_add5(x, y):
print("op_add5")
return x + y

View File

@@ -5,11 +5,3 @@ A = 3.14 * r ** 2 # FURB152
C = 6.28 * r # FURB152
e = 2.71 # FURB152
r = 3.15 # OK
r = 3.141 # FURB152
r = 3.1415 # FURB152
e = 2.7 # OK

View File

@@ -16,8 +16,6 @@ special_log(1, 2)
special_log(1, 10)
special_log(1, math.e)
special_log(1, special_e)
math.log(1, 2.0)
math.log(1, 10.0)
# Ok.
math.log2(1)
@@ -47,6 +45,3 @@ def log(*args):
log(1, 2)
log(1, 10)
log(1, math.e)
math.log(1, 2.0001)
math.log(1, 10.0001)

View File

@@ -1,57 +0,0 @@
import hashlib
from hashlib import (
blake2b,
blake2s,
md5,
sha1,
sha3_224,
sha3_256,
sha3_384,
sha3_512,
sha224,
)
from hashlib import sha256
from hashlib import sha256 as hash_algo
from hashlib import sha384, sha512, shake_128, shake_256
# these will match
blake2b().digest().hex()
blake2s().digest().hex()
md5().digest().hex()
sha1().digest().hex()
sha224().digest().hex()
sha256().digest().hex()
sha384().digest().hex()
sha3_224().digest().hex()
sha3_256().digest().hex()
sha3_384().digest().hex()
sha3_512().digest().hex()
sha512().digest().hex()
shake_128().digest(10).hex()
shake_256().digest(10).hex()
hashlib.sha256().digest().hex()
sha256(b"text").digest().hex()
hash_algo().digest().hex()
# not yet supported
h = sha256()
h.digest().hex()
# these will not
sha256().digest()
sha256().digest().hex("_")
sha256().digest().hex(bytes_per_sep=4)
sha256().hexdigest()
class Hash:
def digest(self) -> bytes:
return b""
Hash().digest().hex()

View File

@@ -63,29 +63,11 @@ def f():
tasks = [asyncio.create_task(task) for task in tasks]
# Error
# OK (false negative)
def f():
task = asyncio.create_task(coordinator.ws_connect())
# Error
def f():
loop = asyncio.get_running_loop()
task: asyncio.Task = loop.create_task(coordinator.ws_connect())
# OK (potential false negative)
def f():
task = asyncio.create_task(coordinator.ws_connect())
background_tasks.add(task)
# OK
async def f():
task = asyncio.create_task(coordinator.ws_connect())
await task
# OK (potential false negative)
def f():
do_nothing_with_the_task(asyncio.create_task(coordinator.ws_connect()))
@@ -106,59 +88,3 @@ def f():
def f():
loop = asyncio.get_running_loop()
loop.do_thing(coordinator.ws_connect())
# OK
async def f():
task = unused = asyncio.create_task(coordinator.ws_connect())
await task
# OK (false negative)
async def f():
task = unused = asyncio.create_task(coordinator.ws_connect())
# OK
async def f():
task[i] = asyncio.create_task(coordinator.ws_connect())
# OK
async def f(x: int):
if x > 0:
task = asyncio.create_task(make_request())
else:
task = asyncio.create_task(make_request())
await task
# OK
async def f(x: bool):
if x:
t = asyncio.create_task(asyncio.sleep(1))
else:
t = None
try:
await asyncio.sleep(1)
finally:
if t:
await t
# Error
async def f(x: bool):
if x:
t = asyncio.create_task(asyncio.sleep(1))
else:
t = None
# OK
async def f(x: bool):
global T
if x:
T = asyncio.create_task(asyncio.sleep(1))
else:
T = None

View File

@@ -59,11 +59,3 @@ class F(BaseSettings):
without_annotation = []
class_variable: ClassVar[list[int]] = []
final_variable: Final[list[int]] = []
class G(F):
mutable_default: list[int] = []
immutable_annotation: Sequence[int] = []
without_annotation = []
class_variable: ClassVar[list[int]] = []
final_variable: Final[list[int]] = []

View File

@@ -1,8 +0,0 @@
from typing import Never, NoReturn, Union
Union[Never, int]
Union[NoReturn, int]
Never | int
NoReturn | int
Union[Union[Never, int], Union[NoReturn, int]]
Union[NoReturn, int, float]

View File

@@ -23,6 +23,3 @@ print(a) # noqa: E501, F821 # comment
print(a) # noqa: E501, F821 # comment
print(a) # noqa: E501, F821 comment
print(a) # noqa: E501, F821 comment
print(a) # comment with unicode µ # noqa: E501
print(a) # comment with unicode µ # noqa: E501, F821

View File

@@ -2,7 +2,7 @@ use ruff_python_ast::Expr;
use crate::checkers::ast::Checker;
use crate::codes::Rule;
use crate::rules::{flake8_pie, pylint, refurb};
use crate::rules::{flake8_pie, pylint};
/// Run lint rules over all deferred lambdas in the [`SemanticModel`].
pub(crate) fn deferred_lambdas(checker: &mut Checker) {
@@ -21,9 +21,6 @@ pub(crate) fn deferred_lambdas(checker: &mut Checker) {
if checker.enabled(Rule::ReimplementedContainerBuiltin) {
flake8_pie::rules::reimplemented_container_builtin(checker, lambda);
}
if checker.enabled(Rule::ReimplementedOperator) {
refurb::rules::reimplemented_operator(checker, &lambda.into());
}
}
}
}

View File

@@ -5,21 +5,16 @@ use ruff_text_size::Ranged;
use crate::checkers::ast::Checker;
use crate::codes::Rule;
use crate::rules::{
flake8_pyi, flake8_type_checking, flake8_unused_arguments, pyflakes, pylint, ruff,
};
use crate::rules::{flake8_pyi, flake8_type_checking, flake8_unused_arguments, pyflakes, pylint};
/// Run lint rules over all deferred scopes in the [`SemanticModel`].
pub(crate) fn deferred_scopes(checker: &mut Checker) {
if !checker.any_enabled(&[
Rule::AsyncioDanglingTask,
Rule::GlobalVariableNotAssigned,
Rule::ImportShadowedByLoopVar,
Rule::NoSelfUse,
Rule::RedefinedArgumentFromLocal,
Rule::RedefinedWhileUnused,
Rule::RuntimeImportInTypeCheckingBlock,
Rule::TooManyLocals,
Rule::TypingOnlyFirstPartyImport,
Rule::TypingOnlyStandardLibraryImport,
Rule::TypingOnlyThirdPartyImport,
@@ -36,6 +31,7 @@ pub(crate) fn deferred_scopes(checker: &mut Checker) {
Rule::UnusedPrivateTypedDict,
Rule::UnusedStaticMethodArgument,
Rule::UnusedVariable,
Rule::NoSelfUse,
]) {
return;
}
@@ -63,7 +59,6 @@ pub(crate) fn deferred_scopes(checker: &mut Checker) {
flake8_type_checking::helpers::is_valid_runtime_import(
binding,
&checker.semantic,
&checker.settings.flake8_type_checking,
)
})
.collect()
@@ -273,10 +268,6 @@ pub(crate) fn deferred_scopes(checker: &mut Checker) {
flake8_pyi::rules::unused_private_typed_dict(checker, scope, &mut diagnostics);
}
if checker.enabled(Rule::AsyncioDanglingTask) {
ruff::rules::asyncio_dangling_binding(scope, &checker.semantic, &mut diagnostics);
}
if matches!(scope.kind, ScopeKind::Function(_) | ScopeKind::Lambda(_)) {
if checker.enabled(Rule::UnusedVariable) {
pyflakes::rules::unused_variable(checker, scope, &mut diagnostics);
@@ -344,10 +335,6 @@ pub(crate) fn deferred_scopes(checker: &mut Checker) {
if checker.enabled(Rule::NoSelfUse) {
pylint::rules::no_self_use(checker, scope_id, scope, &mut diagnostics);
}
if checker.enabled(Rule::TooManyLocals) {
pylint::rules::too_many_locals(checker, scope, &mut diagnostics);
}
}
}
checker.diagnostics.extend(diagnostics);

View File

@@ -15,9 +15,8 @@ use crate::rules::{
flake8_comprehensions, flake8_datetimez, flake8_debugger, flake8_django,
flake8_future_annotations, flake8_gettext, flake8_implicit_str_concat, flake8_logging,
flake8_logging_format, flake8_pie, flake8_print, flake8_pyi, flake8_pytest_style, flake8_self,
flake8_simplify, flake8_tidy_imports, flake8_trio, flake8_type_checking, flake8_use_pathlib,
flynt, numpy, pandas_vet, pep8_naming, pycodestyle, pyflakes, pygrep_hooks, pylint, pyupgrade,
refurb, ruff,
flake8_simplify, flake8_tidy_imports, flake8_trio, flake8_use_pathlib, flynt, numpy,
pandas_vet, pep8_naming, pycodestyle, pyflakes, pygrep_hooks, pylint, pyupgrade, refurb, ruff,
};
use crate::settings::types::PythonVersion;
@@ -81,7 +80,6 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) {
Rule::DuplicateUnionMember,
Rule::RedundantLiteralUnion,
Rule::UnnecessaryTypeUnion,
Rule::NeverUnion,
]) {
// Avoid duplicate checks if the parent is a union, since these rules already
// traverse nested unions.
@@ -101,10 +99,6 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) {
}
}
if checker.enabled(Rule::NeverUnion) {
ruff::rules::never_union(checker, expr);
}
if checker.any_enabled(&[
Rule::SysVersionSlice3,
Rule::SysVersion2,
@@ -362,8 +356,6 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) {
Rule::FString,
// flynt
Rule::StaticJoinToFString,
// refurb
Rule::HashlibDigestHex,
]) {
if let Expr::Attribute(ast::ExprAttribute { value, attr, .. }) = func.as_ref() {
let attr = attr.as_str();
@@ -551,7 +543,7 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) {
flake8_bugbear::rules::no_explicit_stacklevel(checker, call);
}
if checker.enabled(Rule::UnnecessaryDictKwargs) {
flake8_pie::rules::unnecessary_dict_kwargs(checker, call);
flake8_pie::rules::unnecessary_dict_kwargs(checker, expr, keywords);
}
if checker.enabled(Rule::UnnecessaryRangeStart) {
flake8_pie::rules::unnecessary_range_start(checker, call);
@@ -589,9 +581,6 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) {
if checker.enabled(Rule::HashlibInsecureHashFunction) {
flake8_bandit::rules::hashlib_insecure_hash_functions(checker, call);
}
if checker.enabled(Rule::HashlibDigestHex) {
refurb::rules::hashlib_digest_hex(checker, call);
}
if checker.enabled(Rule::RequestWithoutTimeout) {
flake8_bandit::rules::request_without_timeout(checker, call);
}
@@ -1159,10 +1148,6 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) {
}
}
if checker.enabled(Rule::NeverUnion) {
ruff::rules::never_union(checker, expr);
}
// Avoid duplicate checks if the parent is a union, since these rules already
// traverse nested unions.
if !checker.semantic.in_nested_union() {
@@ -1180,9 +1165,6 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) {
if checker.enabled(Rule::UnnecessaryTypeUnion) {
flake8_pyi::rules::unnecessary_type_union(checker, expr);
}
if checker.enabled(Rule::RuntimeStringUnion) {
flake8_type_checking::rules::runtime_string_union(checker, expr);
}
}
}
Expr::UnaryOp(
@@ -1288,12 +1270,32 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) {
refurb::rules::math_constant(checker, number_literal);
}
}
Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) => {
Expr::BytesLiteral(_) => {
if checker.source_type.is_stub() && checker.enabled(Rule::StringOrBytesTooLong) {
flake8_pyi::rules::string_or_bytes_too_long(checker, expr);
}
}
Expr::StringLiteral(string) => {
if checker.enabled(Rule::HardcodedBindAllInterfaces) {
if let Some(diagnostic) =
flake8_bandit::rules::hardcoded_bind_all_interfaces(string)
{
checker.diagnostics.push(diagnostic);
}
}
if checker.enabled(Rule::HardcodedTempFile) {
flake8_bandit::rules::hardcoded_tmp_directory(checker, string);
}
if checker.enabled(Rule::UnicodeKindPrefix) {
for string_part in value {
for string_part in string.value.parts() {
pyupgrade::rules::unicode_kind_prefix(checker, string_part);
}
}
if checker.source_type.is_stub() {
if checker.enabled(Rule::StringOrBytesTooLong) {
flake8_pyi::rules::string_or_bytes_too_long(checker, expr);
}
}
}
Expr::IfExp(
if_exp @ ast::ExprIfExp {
@@ -1331,9 +1333,6 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) {
if checker.enabled(Rule::UnnecessaryListIndexLookup) {
pylint::rules::unnecessary_list_index_lookup_comprehension(checker, expr);
}
if checker.enabled(Rule::UnnecessaryDictIndexLookup) {
pylint::rules::unnecessary_dict_index_lookup_comprehension(checker, expr);
}
if checker.enabled(Rule::UnnecessaryComprehension) {
flake8_comprehensions::rules::unnecessary_list_set_comprehension(
checker, expr, elt, generators,
@@ -1361,9 +1360,6 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) {
if checker.enabled(Rule::UnnecessaryListIndexLookup) {
pylint::rules::unnecessary_list_index_lookup_comprehension(checker, expr);
}
if checker.enabled(Rule::UnnecessaryDictIndexLookup) {
pylint::rules::unnecessary_dict_index_lookup_comprehension(checker, expr);
}
if checker.enabled(Rule::UnnecessaryComprehension) {
flake8_comprehensions::rules::unnecessary_list_set_comprehension(
checker, expr, elt, generators,
@@ -1390,9 +1386,6 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) {
if checker.enabled(Rule::UnnecessaryListIndexLookup) {
pylint::rules::unnecessary_list_index_lookup_comprehension(checker, expr);
}
if checker.enabled(Rule::UnnecessaryDictIndexLookup) {
pylint::rules::unnecessary_dict_index_lookup_comprehension(checker, expr);
}
if checker.enabled(Rule::UnnecessaryComprehension) {
flake8_comprehensions::rules::unnecessary_dict_comprehension(
checker, expr, key, value, generators,
@@ -1420,9 +1413,6 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) {
if checker.enabled(Rule::UnnecessaryListIndexLookup) {
pylint::rules::unnecessary_list_index_lookup_comprehension(checker, expr);
}
if checker.enabled(Rule::UnnecessaryDictIndexLookup) {
pylint::rules::unnecessary_dict_index_lookup_comprehension(checker, expr);
}
if checker.enabled(Rule::FunctionUsesLoopVariable) {
flake8_bugbear::rules::function_uses_loop_variable(checker, &Node::Expr(expr));
}

View File

@@ -10,7 +10,6 @@ pub(super) use module::module;
pub(super) use parameter::parameter;
pub(super) use parameters::parameters;
pub(super) use statement::statement;
pub(super) use string_like::string_like;
pub(super) use suite::suite;
pub(super) use unresolved_references::unresolved_references;
@@ -26,6 +25,5 @@ mod module;
mod parameter;
mod parameters;
mod statement;
mod string_like;
mod suite;
mod unresolved_references;

View File

@@ -248,10 +248,7 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
pylint::rules::property_with_parameters(checker, stmt, decorator_list, parameters);
}
if checker.enabled(Rule::TooManyArguments) {
pylint::rules::too_many_arguments(checker, function_def);
}
if checker.enabled(Rule::TooManyPositional) {
pylint::rules::too_many_positional(checker, function_def);
pylint::rules::too_many_arguments(checker, parameters, stmt);
}
if checker.enabled(Rule::TooManyReturnStatements) {
if let Some(diagnostic) = pylint::rules::too_many_return_statements(
@@ -368,9 +365,6 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
.diagnostics
.extend(ruff::rules::unreachable::in_function(name, body));
}
if checker.enabled(Rule::ReimplementedOperator) {
refurb::rules::reimplemented_operator(checker, &function_def.into());
}
}
Stmt::Return(_) => {
if checker.enabled(Rule::ReturnOutsideFunction) {
@@ -400,13 +394,27 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
flake8_django::rules::nullable_model_string_field(checker, body);
}
if checker.enabled(Rule::DjangoExcludeWithModelForm) {
flake8_django::rules::exclude_with_model_form(checker, class_def);
if let Some(diagnostic) = flake8_django::rules::exclude_with_model_form(
checker,
arguments.as_deref(),
body,
) {
checker.diagnostics.push(diagnostic);
}
}
if checker.enabled(Rule::DjangoAllWithModelForm) {
flake8_django::rules::all_with_model_form(checker, class_def);
if let Some(diagnostic) =
flake8_django::rules::all_with_model_form(checker, arguments.as_deref(), body)
{
checker.diagnostics.push(diagnostic);
}
}
if checker.enabled(Rule::DjangoUnorderedBodyContentInModel) {
flake8_django::rules::unordered_body_content_in_model(checker, class_def);
flake8_django::rules::unordered_body_content_in_model(
checker,
arguments.as_deref(),
body,
);
}
if !checker.source_type.is_stub() {
if checker.enabled(Rule::DjangoModelWithoutDunderStr) {
@@ -1272,9 +1280,6 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
if checker.enabled(Rule::UnnecessaryListIndexLookup) {
pylint::rules::unnecessary_list_index_lookup(checker, for_stmt);
}
if checker.enabled(Rule::UnnecessaryDictIndexLookup) {
pylint::rules::unnecessary_dict_index_lookup(checker, for_stmt);
}
if !is_async {
if checker.enabled(Rule::ReimplementedBuiltin) {
flake8_simplify::rules::convert_for_loop_to_any_all(checker, stmt);
@@ -1526,14 +1531,6 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
}
}
}
Stmt::TypeAlias(ast::StmtTypeAlias { name, .. }) => {
if checker.enabled(Rule::SnakeCaseTypeAlias) {
flake8_pyi::rules::snake_case_type_alias(checker, name);
}
if checker.enabled(Rule::TSuffixedTypeAlias) {
flake8_pyi::rules::t_suffixed_type_alias(checker, name);
}
}
Stmt::Delete(delete @ ast::StmtDelete { targets, range: _ }) => {
if checker.enabled(Rule::GlobalStatement) {
for target in targets {
@@ -1560,11 +1557,7 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
pylint::rules::named_expr_without_context(checker, value);
}
if checker.enabled(Rule::AsyncioDanglingTask) {
if let Some(diagnostic) =
ruff::rules::asyncio_dangling_task(value, checker.semantic())
{
checker.diagnostics.push(diagnostic);
}
ruff::rules::asyncio_dangling_task(checker, value);
}
if checker.enabled(Rule::RepeatedAppend) {
refurb::rules::repeated_append(checker, stmt);

View File

@@ -1,20 +0,0 @@
use ruff_python_ast::StringLike;
use crate::checkers::ast::Checker;
use crate::codes::Rule;
use crate::rules::{flake8_bandit, flake8_pyi};
/// Run lint rules over a [`StringLike`] syntax nodes.
pub(crate) fn string_like(string_like: StringLike, checker: &mut Checker) {
if checker.enabled(Rule::HardcodedBindAllInterfaces) {
flake8_bandit::rules::hardcoded_bind_all_interfaces(checker, string_like);
}
if checker.enabled(Rule::HardcodedTempFile) {
flake8_bandit::rules::hardcoded_tmp_directory(checker, string_like);
}
if checker.source_type.is_stub() {
if checker.enabled(Rule::StringOrBytesTooLong) {
flake8_pyi::rules::string_or_bytes_too_long(checker, string_like);
}
}
}

View File

@@ -1,66 +0,0 @@
use ruff_python_semantic::{ScopeKind, SemanticModel};
use crate::rules::flake8_type_checking;
use crate::settings::LinterSettings;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(super) enum AnnotationContext {
/// Python will evaluate the annotation at runtime, but it's not _required_ and, as such, could
/// be quoted to convert it into a typing-only annotation.
///
/// For example:
/// ```python
/// from pandas import DataFrame
///
/// def foo() -> DataFrame:
/// ...
/// ```
///
/// Above, Python will evaluate `DataFrame` at runtime in order to add it to `__annotations__`.
RuntimeEvaluated,
/// Python will evaluate the annotation at runtime, and it's required to be available at
/// runtime, as a library (like Pydantic) needs access to it.
RuntimeRequired,
/// The annotation is only evaluated at type-checking time.
TypingOnly,
}
impl AnnotationContext {
pub(super) fn from_model(semantic: &SemanticModel, settings: &LinterSettings) -> Self {
// If the annotation is in a class scope (e.g., an annotated assignment for a
// class field), and that class is marked as annotation as runtime-required.
if semantic
.current_scope()
.kind
.as_class()
.is_some_and(|class_def| {
flake8_type_checking::helpers::runtime_required_class(
class_def,
&settings.flake8_type_checking.runtime_required_base_classes,
&settings.flake8_type_checking.runtime_required_decorators,
semantic,
)
})
{
return Self::RuntimeRequired;
}
// If `__future__` annotations are enabled, then annotations are never evaluated
// at runtime, so we can treat them as typing-only.
if semantic.future_annotations() {
return Self::TypingOnly;
}
// Otherwise, if we're in a class or module scope, then the annotation needs to
// be available at runtime.
// See: https://docs.python.org/3/reference/simple_stmts.html#annotated-assignment-statements
if matches!(
semantic.current_scope().kind,
ScopeKind::Class(_) | ScopeKind::Module
) {
return Self::RuntimeEvaluated;
}
Self::TypingOnly
}
}

View File

@@ -44,12 +44,12 @@ use ruff_python_ast::helpers::{
};
use ruff_python_ast::identifier::Identifier;
use ruff_python_ast::str::trailing_quote;
use ruff_python_ast::visitor::{walk_except_handler, walk_f_string_element, walk_pattern, Visitor};
use ruff_python_ast::visitor::{walk_except_handler, walk_pattern, Visitor};
use ruff_python_ast::{helpers, str, visitor, PySourceType};
use ruff_python_codegen::{Generator, Quote, Stylist};
use ruff_python_index::Indexer;
use ruff_python_parser::typing::{parse_type_annotation, AnnotationKind};
use ruff_python_semantic::analyze::{imports, typing, visibility};
use ruff_python_semantic::analyze::{typing, visibility};
use ruff_python_semantic::{
BindingFlags, BindingId, BindingKind, Exceptions, Export, FromImport, Globals, Import, Module,
ModuleKind, NodeId, ScopeId, ScopeKind, SemanticModel, SemanticModelFlags, Snapshot,
@@ -58,7 +58,6 @@ use ruff_python_semantic::{
use ruff_python_stdlib::builtins::{IPYTHON_BUILTINS, MAGIC_GLOBALS, PYTHON_BUILTINS};
use ruff_source_file::Locator;
use crate::checkers::ast::annotation::AnnotationContext;
use crate::checkers::ast::deferred::Deferred;
use crate::docstrings::extraction::ExtractionTarget;
use crate::importer::Importer;
@@ -69,7 +68,6 @@ use crate::settings::{flags, LinterSettings};
use crate::{docstrings, noqa};
mod analyze;
mod annotation;
mod deferred;
pub(crate) struct Checker<'a> {
@@ -287,18 +285,7 @@ where
// Track whether we've seen docstrings, non-imports, etc.
match stmt {
Stmt::Expr(ast::StmtExpr { value, .. })
if !self
.semantic
.flags
.intersects(SemanticModelFlags::MODULE_DOCSTRING)
&& value.is_string_literal_expr() =>
{
self.semantic.flags |= SemanticModelFlags::MODULE_DOCSTRING;
}
Stmt::ImportFrom(ast::StmtImportFrom { module, names, .. }) => {
self.semantic.flags |= SemanticModelFlags::MODULE_DOCSTRING;
// Allow __future__ imports until we see a non-__future__ import.
if let Some("__future__") = module.as_deref() {
if names
@@ -312,18 +299,13 @@ where
}
}
Stmt::Import(_) => {
self.semantic.flags |= SemanticModelFlags::MODULE_DOCSTRING;
self.semantic.flags |= SemanticModelFlags::FUTURES_BOUNDARY;
}
_ => {
self.semantic.flags |= SemanticModelFlags::MODULE_DOCSTRING;
self.semantic.flags |= SemanticModelFlags::FUTURES_BOUNDARY;
if !(self.semantic.seen_import_boundary()
|| helpers::is_assignment_to_a_dunder(stmt)
|| helpers::in_nested_block(self.semantic.current_statements())
|| imports::is_matplotlib_activation(stmt, self.semantic())
|| self.settings.preview.is_enabled()
&& imports::is_sys_path_modification(stmt, self.semantic()))
if !self.semantic.seen_import_boundary()
&& !helpers::is_assignment_to_a_dunder(stmt)
&& !helpers::in_nested_block(self.semantic.current_statements())
{
self.semantic.flags |= SemanticModelFlags::IMPORT_BOUNDARY;
}
@@ -530,10 +512,8 @@ where
.chain(&parameters.kwonlyargs)
{
if let Some(expr) = &parameter_with_default.parameter.annotation {
if singledispatch {
self.visit_runtime_required_annotation(expr);
} else if runtime_annotation {
self.visit_runtime_evaluated_annotation(expr);
if runtime_annotation || singledispatch {
self.visit_runtime_annotation(expr);
} else {
self.visit_annotation(expr);
};
@@ -546,7 +526,7 @@ where
if let Some(arg) = &parameters.vararg {
if let Some(expr) = &arg.annotation {
if runtime_annotation {
self.visit_runtime_evaluated_annotation(expr);
self.visit_runtime_annotation(expr);
} else {
self.visit_annotation(expr);
};
@@ -555,7 +535,7 @@ where
if let Some(arg) = &parameters.kwarg {
if let Some(expr) = &arg.annotation {
if runtime_annotation {
self.visit_runtime_evaluated_annotation(expr);
self.visit_runtime_annotation(expr);
} else {
self.visit_annotation(expr);
};
@@ -563,7 +543,7 @@ where
}
for expr in returns {
if runtime_annotation {
self.visit_runtime_evaluated_annotation(expr);
self.visit_runtime_annotation(expr);
} else {
self.visit_annotation(expr);
};
@@ -694,16 +674,40 @@ where
value,
..
}) => {
match AnnotationContext::from_model(&self.semantic, self.settings) {
AnnotationContext::RuntimeRequired => {
self.visit_runtime_required_annotation(annotation);
}
AnnotationContext::RuntimeEvaluated => {
self.visit_runtime_evaluated_annotation(annotation);
}
AnnotationContext::TypingOnly => self.visit_annotation(annotation),
}
// If we're in a class or module scope, then the annotation needs to be
// available at runtime.
// See: https://docs.python.org/3/reference/simple_stmts.html#annotated-assignment-statements
let runtime_annotation = if self.semantic.future_annotations() {
self.semantic
.current_scope()
.kind
.as_class()
.is_some_and(|class_def| {
flake8_type_checking::helpers::runtime_evaluated_class(
class_def,
&self
.settings
.flake8_type_checking
.runtime_evaluated_base_classes,
&self
.settings
.flake8_type_checking
.runtime_evaluated_decorators,
&self.semantic,
)
})
} else {
matches!(
self.semantic.current_scope().kind,
ScopeKind::Class(_) | ScopeKind::Module
)
};
if runtime_annotation {
self.visit_runtime_annotation(annotation);
} else {
self.visit_annotation(annotation);
}
if let Some(expr) = value {
if self.semantic.match_typing_expr(annotation, "TypeAlias") {
self.visit_type_definition(expr);
@@ -811,7 +815,8 @@ where
fn visit_expr(&mut self, expr: &'b Expr) {
// Step 0: Pre-processing
if !self.semantic.in_typing_literal()
if !self.semantic.in_f_string()
&& !self.semantic.in_literal()
&& !self.semantic.in_deferred_type_definition()
&& self.semantic.in_type_definition()
&& self.semantic.future_annotations()
@@ -1193,7 +1198,7 @@ where
) {
// Ex) Literal["Class"]
Some(typing::SubscriptKind::Literal) => {
self.semantic.flags |= SemanticModelFlags::TYPING_LITERAL;
self.semantic.flags |= SemanticModelFlags::LITERAL;
self.visit_expr(slice);
self.visit_expr_context(ctx);
@@ -1233,7 +1238,10 @@ where
}
}
Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) => {
if self.semantic.in_type_definition() && !self.semantic.in_typing_literal() {
if self.semantic.in_type_definition()
&& !self.semantic.in_literal()
&& !self.semantic.in_f_string()
{
self.deferred.string_type_definitions.push((
expr.range(),
value.to_str(),
@@ -1263,13 +1271,6 @@ where
// Step 4: Analysis
analyze::expression(expr, self);
match expr {
Expr::StringLiteral(string_literal) => {
analyze::string_like(string_literal.into(), self);
}
Expr::BytesLiteral(bytes_literal) => analyze::string_like(bytes_literal.into(), self),
_ => {}
}
self.semantic.flags = flags_snapshot;
self.semantic.pop_node();
@@ -1325,6 +1326,17 @@ where
self.semantic.flags = flags_snapshot;
}
fn visit_format_spec(&mut self, format_spec: &'b Expr) {
match format_spec {
Expr::FString(ast::ExprFString { value, .. }) => {
for expr in value.elements() {
self.visit_expr(expr);
}
}
_ => unreachable!("Unexpected expression for format_spec"),
}
}
fn visit_parameters(&mut self, parameters: &'b Parameters) {
// Step 1: Binding.
// Bind, but intentionally avoid walking default expressions, as we handle them
@@ -1434,22 +1446,15 @@ where
.push((bound, self.semantic.snapshot()));
}
}
fn visit_f_string_element(&mut self, f_string_element: &'b ast::FStringElement) {
// Step 2: Traversal
walk_f_string_element(self, f_string_element);
// Step 4: Analysis
if let Some(literal) = f_string_element.as_literal() {
analyze::string_like(literal.into(), self);
}
}
}
impl<'a> Checker<'a> {
/// Visit a [`Module`]. Returns `true` if the module contains a module-level docstring.
fn visit_module(&mut self, python_ast: &'a Suite) {
fn visit_module(&mut self, python_ast: &'a Suite) -> bool {
analyze::module(python_ast, self);
let docstring = docstrings::extraction::docstring_from(python_ast);
docstring.is_some()
}
/// Visit a list of [`Comprehension`] nodes, assumed to be the comprehensions that compose a
@@ -1517,18 +1522,10 @@ impl<'a> Checker<'a> {
self.semantic.flags = snapshot;
}
/// Visit an [`Expr`], and treat it as a runtime-evaluated type annotation.
fn visit_runtime_evaluated_annotation(&mut self, expr: &'a Expr) {
let snapshot = self.semantic.flags;
self.semantic.flags |= SemanticModelFlags::RUNTIME_EVALUATED_ANNOTATION;
self.visit_type_definition(expr);
self.semantic.flags = snapshot;
}
/// Visit an [`Expr`], and treat it as a runtime-required type annotation.
fn visit_runtime_required_annotation(&mut self, expr: &'a Expr) {
fn visit_runtime_annotation(&mut self, expr: &'a Expr) {
let snapshot = self.semantic.flags;
self.semantic.flags |= SemanticModelFlags::RUNTIME_REQUIRED_ANNOTATION;
self.semantic.flags |= SemanticModelFlags::RUNTIME_ANNOTATION;
self.visit_type_definition(expr);
self.semantic.flags = snapshot;
}
@@ -1755,13 +1752,10 @@ impl<'a> Checker<'a> {
return;
}
// If the expression is the left-hand side of a walrus operator, then it's a named
// expression assignment.
if self
.semantic
.current_expressions()
.filter_map(Expr::as_named_expr_expr)
.any(|parent| parent.target.as_ref() == expr)
.any(Expr::is_named_expr_expr)
{
self.add_binding(id, expr.range(), BindingKind::NamedExprAssignment, flags);
return;
@@ -2016,19 +2010,23 @@ pub(crate) fn check_ast(
);
checker.bind_builtins();
// Check for module docstring.
let python_ast = if checker.visit_module(python_ast) {
&python_ast[1..]
} else {
python_ast
};
// Iterate over the AST.
checker.visit_module(python_ast);
checker.visit_body(python_ast);
// Visit any deferred syntax nodes. Take care to visit in order, such that we avoid adding
// new deferred nodes after visiting nodes of that kind. For example, visiting a deferred
// function can add a deferred lambda, but the opposite is not true.
// Visit any deferred syntax nodes.
checker.visit_deferred_functions();
checker.visit_deferred_type_param_definitions();
checker.visit_deferred_lambdas();
checker.visit_deferred_future_type_definitions();
checker.visit_deferred_type_param_definitions();
let allocator = typed_arena::Arena::new();
checker.visit_deferred_string_type_definitions(&allocator);
checker.visit_deferred_lambdas();
checker.visit_exports();
// Check docstrings, bindings, and unresolved references.

View File

@@ -1,4 +1,4 @@
use ruff_diagnostics::Diagnostic;
use ruff_diagnostics::{Diagnostic, DiagnosticKind};
use ruff_python_codegen::Stylist;
use ruff_python_parser::lexer::LexResult;
use ruff_python_parser::TokenKind;
@@ -97,7 +97,7 @@ pub(crate) fn check_logical_lines(
indent_size,
) {
if settings.rules.enabled(kind.rule()) {
context.push_diagnostic(Diagnostic::new(kind, range));
context.push(kind, range);
}
}
@@ -123,6 +123,18 @@ impl<'a> LogicalLinesContext<'a> {
}
}
pub(crate) fn push<K: Into<DiagnosticKind>>(&mut self, kind: K, range: TextRange) {
let kind = kind.into();
if self.settings.rules.enabled(kind.rule()) {
self.diagnostics.push(Diagnostic {
kind,
range,
fix: None,
parent: None,
});
}
}
pub(crate) fn push_diagnostic(&mut self, diagnostic: Diagnostic) {
if self.settings.rules.enabled(diagnostic.kind.rule()) {
self.diagnostics.push(diagnostic);

View File

@@ -3,10 +3,10 @@
use std::path::Path;
use itertools::Itertools;
use ruff_text_size::{Ranged, TextLen, TextRange};
use ruff_text_size::{Ranged, TextLen, TextRange, TextSize};
use ruff_diagnostics::{Diagnostic, Edit, Fix};
use ruff_python_trivia::{CommentRanges, PythonWhitespace};
use ruff_python_trivia::CommentRanges;
use ruff_source_file::Locator;
use crate::noqa;
@@ -200,11 +200,17 @@ fn delete_noqa(range: TextRange, locator: &Locator) -> Edit {
// Compute the leading space.
let prefix = locator.slice(TextRange::new(line_range.start(), range.start()));
let leading_space_len = prefix.text_len() - prefix.trim_whitespace_end().text_len();
let leading_space = prefix
.rfind(|c: char| !c.is_whitespace())
.map_or(prefix.len(), |i| prefix.len() - i - 1);
let leading_space_len = TextSize::try_from(leading_space).unwrap();
// Compute the trailing space.
let suffix = locator.slice(TextRange::new(range.end(), line_range.end()));
let trailing_space_len = suffix.text_len() - suffix.trim_whitespace_start().text_len();
let trailing_space = suffix
.find(|c: char| !c.is_whitespace())
.map_or(suffix.len(), |i| i);
let trailing_space_len = TextSize::try_from(trailing_space).unwrap();
// Ex) `# noqa`
if line_range

View File

@@ -252,17 +252,14 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> {
(Pylint, "R0911") => (RuleGroup::Stable, rules::pylint::rules::TooManyReturnStatements),
(Pylint, "R0912") => (RuleGroup::Stable, rules::pylint::rules::TooManyBranches),
(Pylint, "R0913") => (RuleGroup::Stable, rules::pylint::rules::TooManyArguments),
(Pylint, "R0914") => (RuleGroup::Preview, rules::pylint::rules::TooManyLocals),
(Pylint, "R0915") => (RuleGroup::Stable, rules::pylint::rules::TooManyStatements),
(Pylint, "R0916") => (RuleGroup::Preview, rules::pylint::rules::TooManyBooleanExpressions),
(Pylint, "R0917") => (RuleGroup::Preview, rules::pylint::rules::TooManyPositional),
(Pylint, "R1701") => (RuleGroup::Stable, rules::pylint::rules::RepeatedIsinstanceCalls),
(Pylint, "R1704") => (RuleGroup::Preview, rules::pylint::rules::RedefinedArgumentFromLocal),
(Pylint, "R1711") => (RuleGroup::Stable, rules::pylint::rules::UselessReturn),
(Pylint, "R1714") => (RuleGroup::Stable, rules::pylint::rules::RepeatedEqualityComparison),
(Pylint, "R1706") => (RuleGroup::Preview, rules::pylint::rules::AndOrTernary),
(Pylint, "R1722") => (RuleGroup::Stable, rules::pylint::rules::SysExitAlias),
(Pylint, "R1733") => (RuleGroup::Preview, rules::pylint::rules::UnnecessaryDictIndexLookup),
(Pylint, "R1736") => (RuleGroup::Preview, rules::pylint::rules::UnnecessaryListIndexLookup),
(Pylint, "R2004") => (RuleGroup::Stable, rules::pylint::rules::MagicValueComparison),
(Pylint, "R5501") => (RuleGroup::Stable, rules::pylint::rules::CollapsibleElseIf),
@@ -808,7 +805,6 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> {
(Flake8TypeChecking, "003") => (RuleGroup::Stable, rules::flake8_type_checking::rules::TypingOnlyStandardLibraryImport),
(Flake8TypeChecking, "004") => (RuleGroup::Stable, rules::flake8_type_checking::rules::RuntimeImportInTypeCheckingBlock),
(Flake8TypeChecking, "005") => (RuleGroup::Stable, rules::flake8_type_checking::rules::EmptyTypeCheckingBlock),
(Flake8TypeChecking, "006") => (RuleGroup::Preview, rules::flake8_type_checking::rules::RuntimeStringUnion),
// tryceratops
(Tryceratops, "002") => (RuleGroup::Stable, rules::tryceratops::rules::RaiseVanillaClass),
@@ -901,7 +897,6 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> {
(Ruff, "017") => (RuleGroup::Nursery, rules::ruff::rules::QuadraticListSummation),
(Ruff, "018") => (RuleGroup::Preview, rules::ruff::rules::AssignmentInAssert),
(Ruff, "019") => (RuleGroup::Preview, rules::ruff::rules::UnnecessaryKeyCheck),
(Ruff, "020") => (RuleGroup::Preview, rules::ruff::rules::NeverUnion),
(Ruff, "100") => (RuleGroup::Stable, rules::ruff::rules::UnusedNOQA),
(Ruff, "200") => (RuleGroup::Stable, rules::ruff::rules::InvalidPyprojectToml),
@@ -954,7 +949,6 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> {
(Refurb, "105") => (RuleGroup::Preview, rules::refurb::rules::PrintEmptyString),
#[allow(deprecated)]
(Refurb, "113") => (RuleGroup::Nursery, rules::refurb::rules::RepeatedAppend),
(Refurb, "118") => (RuleGroup::Preview, rules::refurb::rules::ReimplementedOperator),
#[allow(deprecated)]
(Refurb, "131") => (RuleGroup::Nursery, rules::refurb::rules::DeleteFullSlice),
#[allow(deprecated)]
@@ -969,7 +963,6 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> {
(Refurb, "169") => (RuleGroup::Preview, rules::refurb::rules::TypeNoneComparison),
(Refurb, "171") => (RuleGroup::Preview, rules::refurb::rules::SingleItemMembershipTest),
(Refurb, "177") => (RuleGroup::Preview, rules::refurb::rules::ImplicitCwd),
(Refurb, "181") => (RuleGroup::Preview, rules::refurb::rules::HashlibDigestHex),
// flake8-logging
(Flake8Logging, "001") => (RuleGroup::Preview, rules::flake8_logging::rules::DirectLoggerInstantiation),

View File

@@ -3,14 +3,12 @@
use anyhow::{Context, Result};
use ruff_diagnostics::Edit;
use ruff_python_ast::parenthesize::parenthesized_range;
use ruff_python_ast::AnyNodeRef;
use ruff_python_ast::{self as ast, Arguments, ExceptHandler, Stmt};
use ruff_python_ast::{AnyNodeRef, ArgOrKeyword};
use ruff_python_codegen::Stylist;
use ruff_python_index::Indexer;
use ruff_python_trivia::{
has_leading_content, is_python_whitespace, CommentRanges, PythonWhitespace, SimpleTokenKind,
SimpleTokenizer,
has_leading_content, is_python_whitespace, PythonWhitespace, SimpleTokenKind, SimpleTokenizer,
};
use ruff_source_file::{Locator, NewlineWithTrailingNewline, UniversalNewlines};
use ruff_text_size::{Ranged, TextLen, TextRange, TextSize};
@@ -140,32 +138,6 @@ pub(crate) fn remove_argument<T: Ranged>(
}
}
/// Generic function to add arguments or keyword arguments to function calls.
pub(crate) fn add_argument(
argument: &str,
arguments: &Arguments,
comment_ranges: &CommentRanges,
source: &str,
) -> Edit {
if let Some(last) = arguments.arguments_source_order().last() {
// Case 1: existing arguments, so append after the last argument.
let last = parenthesized_range(
match last {
ArgOrKeyword::Arg(arg) => arg.into(),
ArgOrKeyword::Keyword(keyword) => (&keyword.value).into(),
},
arguments.into(),
comment_ranges,
source,
)
.unwrap_or(last.range());
Edit::insertion(format!(", {argument}"), last.end())
} else {
// Case 2: no arguments. Add argument, without any trailing comma.
Edit::insertion(argument.to_string(), arguments.start() + TextSize::from(1))
}
}
/// Determine if a vector contains only one, specific element.
fn is_only<T: PartialEq>(vec: &[T], value: &T) -> bool {
vec.len() == 1 && vec[0] == *value

Some files were not shown because too many files have changed in this diff Show More