Compare commits

...

39 Commits

Author SHA1 Message Date
Charlie Marsh
edd0e16a02 Bump version to 0.0.235 2023-01-25 18:28:27 -05:00
Charlie Marsh
fdccb6ec1c Fix conflicting error message warning (#2182) 2023-01-25 18:26:43 -05:00
Anders Kaseorg
c00b8b6d2d Remove stray parenthesis from fixed errors message (#2181)
Signed-off-by: Anders Kaseorg <andersk@mit.edu>

Signed-off-by: Anders Kaseorg <andersk@mit.edu>
2023-01-25 18:15:12 -05:00
Simon Brugman
52201422ae fix: platform-independent newlines 2023-01-25 18:00:39 -05:00
Simon Brugman
d7fe1eeba0 fix: platform-independent paths 2023-01-25 18:00:39 -05:00
Simon Brugman
5835d719c4 ci: enable windows testing in Github Actions 2023-01-25 18:00:39 -05:00
Simon Brugman
c859ac4933 refactor: test ground truth update for new macro 2023-01-25 18:00:39 -05:00
Simon Brugman
e9c1089ddc refactor: tests use new marco 2023-01-25 18:00:39 -05:00
Simon Brugman
413acdf83c feat: introduce macro for testing snap files across platforms 2023-01-25 18:00:39 -05:00
Charlie Marsh
16d2ece87d Restore single-file license (#2180)
These were split into per-project licenses in #1648, but I don't like that they're no longer included in the distribution (due to current limitations in the `pyproject.toml` spec).
2023-01-25 17:59:12 -05:00
Anders Kaseorg
823f1c5b6a Avoid duplicate CI runs triggered by pushes to pull requests (#2178)
https://github.com/charliermarsh/ruff/pull/2157#discussion_r1087179996

Signed-off-by: Anders Kaseorg <andersk@mit.edu>

Signed-off-by: Anders Kaseorg <andersk@mit.edu>
2023-01-25 17:45:07 -05:00
Charlie Marsh
9b07d0bd92 Bump version to 0.0.234 2023-01-25 16:55:57 -05:00
Charlie Marsh
23525a8ea0 Actually, rename TYP rules to TCH (#2176) 2023-01-25 16:52:49 -05:00
Charlie Marsh
6ede030700 Allow manual releases for pre-release testing 2023-01-25 16:37:04 -05:00
Charlie Marsh
44f3e5013d Add flake8-type-checking license 2023-01-25 16:27:18 -05:00
Charlie Marsh
35cf9e242e Rename TYP rules to TYC (#2175) 2023-01-25 16:26:22 -05:00
Charlie Marsh
d5dff11d4b Avoid reraise-no-cause for explicit reraises (#2174) 2023-01-25 15:51:24 -05:00
Charlie Marsh
8e1fac620e Add flake8-builtins options to README (#2173) 2023-01-25 15:43:26 -05:00
Aarni Koskela
0da691c0d5 Add Babel to readme (#2170) 2023-01-25 15:21:26 -05:00
Hugo van Kemenade
233415921b Add colour to CI for readability 2023-01-25 15:21:10 -05:00
Hugo van Kemenade
81141e2a73 Bump GitHub Actions 2023-01-25 15:21:10 -05:00
Hugo van Kemenade
6e255ad53c Allow testing feature branches 2023-01-25 15:21:10 -05:00
Hugo van Kemenade
6d87adbcc0 Fix singular and plural for error(s) 2023-01-25 15:21:10 -05:00
Florian Best
43a8ce6c89 fix: avoid flagging unused loop variable (B007) with globals(), vars() or eval() (#2166) 2023-01-25 15:18:58 -05:00
Charlie Marsh
a978706dce Re-add error wrapper in main.rs (#2168) 2023-01-25 15:11:24 -05:00
Florian Best
dc1aa8dd1d Suggest input format in error case (#2167) 2023-01-25 14:55:04 -05:00
Charlie Marsh
662e29b1ce Avoid re-resolving settings for repeated paths (#2165)
After this change:

```shell
> time cargo run -- -n $(find ../django -type f -name '*.py')`
8.85s user 0.20s system 498% cpu 1.814 total
> time cargo run -- -n ../django
8.95s user 0.23s system 507% cpu 1.811 total
```

I also verified that we only hit the creation path once via some manual logging.

Closes #2154.
2023-01-25 13:38:33 -05:00
Charlie Marsh
6978dcf035 Add an FAQ on autofix (#2163) 2023-01-25 13:09:16 -05:00
Charlie Marsh
0e6f513607 Avoid prefer-type-error (TRY004) with intermediary control flow (#2162) 2023-01-25 13:00:59 -05:00
Charlie Marsh
02421d02f5 Avoid flagging unused loop variable (B007) with locals() (#2161) 2023-01-25 12:53:35 -05:00
Charlie Marsh
38de46ae3c Treat Python 3.7 as minimum supported version (#2159) 2023-01-25 12:36:50 -05:00
Martin Fischer
f6fd702d41 Add #![warn(clippy::pedantic)] to lib.rs and main.rs files
We already enforced pedantic clippy lints via the
following command in .github/workflows/ci.yaml:

    cargo clippy --workspace --all-targets --all-features -- -D warnings -W clippy::pedantic

Additionally adding #![warn(clippy::pedantic)] to all main.rs and lib.rs
has the benefit that violations of pedantic clippy lints are also
reported when just running `cargo clippy` without any arguments and
are thereby also picked up by LSP[1] servers such as rust-analyzer[2].
However for rust-analyzer to run clippy you'll have to configure:

    "rust-analyzer.check.command": "clippy",

in your editor.[3]

[1]: https://microsoft.github.io/language-server-protocol/
[2]: https://rust-analyzer.github.io/
[3]: https://rust-analyzer.github.io/manual.html#configuration
2023-01-25 00:40:29 -05:00
Martin Fischer
2125d0bb54 refactor: Move #![forbid(unsafe_code)] attributes up
What's forbidden is more important than which clippy lints are
ignored and more important directives should come first.
2023-01-25 00:40:29 -05:00
Charlie Marsh
63b4f60ba4 Implement typing-only import detection (TYP001, TYP002, TYP003) (#2147) 2023-01-24 23:48:11 -05:00
Charlie Marsh
9eb13bc9da Downgrade recommended pre-commit version to v0.0.231 2023-01-24 23:47:13 -05:00
Charlie Marsh
0758049e49 Implement runtime-import-in-type-checking-block (TYP004) (#2146) 2023-01-24 23:33:26 -05:00
Charlie Marsh
deff503932 Avoid generating dirty call paths (#2144) 2023-01-24 20:40:38 -05:00
Jonathan Plasse
82d7814101 Update .pre-commit-config.yml (#2139) 2023-01-24 19:45:34 -05:00
Eric Roberts
0cac1a0d21 Move is_overlong to helpers (#2137) 2023-01-24 12:45:35 -05:00
420 changed files with 5861 additions and 2314 deletions

View File

@@ -4,7 +4,7 @@ on:
push:
branches: [main]
pull_request:
branches: [main]
workflow_dispatch:
concurrency:
group: ${{ github.workflow }}-${{ github.ref_name }}-${{ github.event.pull_request.number || github.sha }}
@@ -13,6 +13,7 @@ concurrency:
env:
CARGO_INCREMENTAL: 0
CARGO_NET_RETRY: 10
CARGO_TERM_COLOR: always
RUSTUP_MAX_RETRIES: 10
jobs:
@@ -63,8 +64,11 @@ jobs:
- run: cargo clippy -p ruff --target wasm32-unknown-unknown --all-features -- -D warnings -W clippy::pedantic
cargo-test:
name: "cargo test"
runs-on: ubuntu-latest
strategy:
matrix:
os: [ ubuntu-latest, windows-latest ]
runs-on: ${{ matrix.os }}
name: "cargo test | ${{ matrix.os }}"
steps:
- uses: actions/checkout@v3
- uses: actions-rs/toolchain@v1
@@ -75,14 +79,23 @@ jobs:
- uses: Swatinem/rust-cache@v1
- run: cargo install cargo-insta
- run: pip install black[d]==22.12.0
- name: Run tests
- name: Run tests (Ubuntu)
if: ${{ matrix.os == 'ubuntu-latest' }}
run: |
cargo insta test --all --delete-unreferenced-snapshots
git diff --exit-code
- name: Run tests (Windows)
if: ${{ matrix.os == 'windows-latest' }}
shell: bash
run: |
cargo insta test --all
git diff --exit-code
- run: cargo test --package ruff_cli --test black_compatibility_test -- --ignored
# Check for broken links in the documentation.
# Setting RUSTDOCFLAGS because `cargo doc --check` isn't yet implemented (https://github.com/rust-lang/cargo/issues/10025).
- run: RUSTDOCFLAGS="-D warnings" cargo doc --all --no-deps
- run: cargo doc --all --no-deps
env:
# Setting RUSTDOCFLAGS because `cargo doc --check` isn't yet implemented (https://github.com/rust-lang/cargo/issues/10025).
RUSTDOCFLAGS: "-D warnings"
scripts:
name: "test scripts"
@@ -153,7 +166,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout Actions Repository
uses: actions/checkout@v2
uses: actions/checkout@v3
- name: Check spelling of file.txt
uses: crate-ci/typos@master

View File

@@ -12,6 +12,7 @@ env:
PYTHON_VERSION: "3.7" # to build abi3 wheels
CARGO_INCREMENTAL: 0
CARGO_NET_RETRY: 10
CARGO_TERM_COLOR: always
RUSTUP_MAX_RETRIES: 10
jobs:
@@ -38,7 +39,7 @@ jobs:
run: |
pip install dist/${{ env.CRATE_NAME }}-*.whl --force-reinstall
- name: Upload wheels
uses: actions/upload-artifact@v2
uses: actions/upload-artifact@v3
with:
name: wheels
path: dist
@@ -64,7 +65,7 @@ jobs:
run: |
pip install dist/${{ env.CRATE_NAME }}-*universal2.whl --force-reinstall
- name: Upload wheels
uses: actions/upload-artifact@v2
uses: actions/upload-artifact@v3
with:
name: wheels
path: dist
@@ -96,7 +97,7 @@ jobs:
run: |
python -m pip install dist/${{ env.CRATE_NAME }}-*.whl --force-reinstall
- name: Upload wheels
uses: actions/upload-artifact@v2
uses: actions/upload-artifact@v3
with:
name: wheels
path: dist
@@ -123,7 +124,7 @@ jobs:
run: |
pip install dist/${{ env.CRATE_NAME }}-*.whl --force-reinstall
- name: Upload wheels
uses: actions/upload-artifact@v2
uses: actions/upload-artifact@v3
with:
name: wheels
path: dist
@@ -144,7 +145,7 @@ jobs:
target: ${{ matrix.target }}
manylinux: auto
args: --no-default-features --release --out dist -m ./${{ env.CRATE_NAME }}/Cargo.toml
- uses: uraimo/run-on-arch-action@v2.0.5
- uses: uraimo/run-on-arch-action@v2.5.0
if: matrix.target != 'ppc64'
name: Install built wheel
with:
@@ -158,7 +159,7 @@ jobs:
run: |
pip3 install ${{ env.PACKAGE_NAME }} --no-index --find-links dist/ --force-reinstall
- name: Upload wheels
uses: actions/upload-artifact@v2
uses: actions/upload-artifact@v3
with:
name: wheels
path: dist
@@ -192,7 +193,7 @@ jobs:
apk add py3-pip
pip3 install ${{ env.PACKAGE_NAME }} --no-index --find-links /io/dist/ --force-reinstall
- name: Upload wheels
uses: actions/upload-artifact@v2
uses: actions/upload-artifact@v3
with:
name: wheels
path: dist
@@ -228,7 +229,7 @@ jobs:
run: |
pip3 install ${{ env.PACKAGE_NAME }} --no-index --find-links dist/ --force-reinstall
- name: Upload wheels
uses: actions/upload-artifact@v2
uses: actions/upload-artifact@v3
with:
name: wheels
path: dist
@@ -262,7 +263,7 @@ jobs:
run: |
pip install dist/${{ env.CRATE_NAME }}-*.whl --force-reinstall
- name: Upload wheels
uses: actions/upload-artifact@v2
uses: actions/upload-artifact@v3
with:
name: wheels
path: dist
@@ -280,7 +281,7 @@ jobs:
- musllinux-cross
- pypy
steps:
- uses: actions/download-artifact@v2
- uses: actions/download-artifact@v3
with:
name: wheels
- uses: actions/setup-python@v4

View File

@@ -8,6 +8,7 @@ on:
env:
CARGO_INCREMENTAL: 0
CARGO_NET_RETRY: 10
CARGO_TERM_COLOR: always
RUSTUP_MAX_RETRIES: 10
jobs:

View File

@@ -1,6 +1,7 @@
name: "[ruff] Release"
on:
workflow_dispatch:
release:
types: [published]
@@ -13,6 +14,7 @@ env:
PYTHON_VERSION: "3.7" # to build abi3 wheels
CARGO_INCREMENTAL: 0
CARGO_NET_RETRY: 10
CARGO_TERM_COLOR: always
RUSTUP_MAX_RETRIES: 10
jobs:
@@ -39,7 +41,7 @@ jobs:
run: |
pip install dist/${{ env.PACKAGE_NAME }}-*.whl --force-reinstall
- name: Upload wheels
uses: actions/upload-artifact@v2
uses: actions/upload-artifact@v3
with:
name: wheels
path: dist
@@ -65,7 +67,7 @@ jobs:
run: |
pip install dist/${{ env.PACKAGE_NAME }}-*universal2.whl --force-reinstall
- name: Upload wheels
uses: actions/upload-artifact@v2
uses: actions/upload-artifact@v3
with:
name: wheels
path: dist
@@ -97,7 +99,7 @@ jobs:
run: |
python -m pip install dist/${{ env.PACKAGE_NAME }}-*.whl --force-reinstall
- name: Upload wheels
uses: actions/upload-artifact@v2
uses: actions/upload-artifact@v3
with:
name: wheels
path: dist
@@ -124,7 +126,7 @@ jobs:
run: |
pip install dist/${{ env.PACKAGE_NAME }}-*.whl --force-reinstall
- name: Upload wheels
uses: actions/upload-artifact@v2
uses: actions/upload-artifact@v3
with:
name: wheels
path: dist
@@ -145,7 +147,7 @@ jobs:
target: ${{ matrix.target }}
manylinux: auto
args: --no-default-features --release --out dist
- uses: uraimo/run-on-arch-action@v2.0.5
- uses: uraimo/run-on-arch-action@v2.5.0
if: matrix.target != 'ppc64'
name: Install built wheel
with:
@@ -159,7 +161,7 @@ jobs:
run: |
pip3 install ${{ env.PACKAGE_NAME }} --no-index --find-links dist/ --force-reinstall
- name: Upload wheels
uses: actions/upload-artifact@v2
uses: actions/upload-artifact@v3
with:
name: wheels
path: dist
@@ -193,7 +195,7 @@ jobs:
apk add py3-pip
pip3 install ${{ env.PACKAGE_NAME }} --no-index --find-links /io/dist/ --force-reinstall
- name: Upload wheels
uses: actions/upload-artifact@v2
uses: actions/upload-artifact@v3
with:
name: wheels
path: dist
@@ -229,7 +231,7 @@ jobs:
run: |
pip3 install ${{ env.PACKAGE_NAME }} --no-index --find-links dist/ --force-reinstall
- name: Upload wheels
uses: actions/upload-artifact@v2
uses: actions/upload-artifact@v3
with:
name: wheels
path: dist
@@ -263,7 +265,7 @@ jobs:
run: |
pip install dist/${{ env.PACKAGE_NAME }}-*.whl --force-reinstall
- name: Upload wheels
uses: actions/upload-artifact@v2
uses: actions/upload-artifact@v3
with:
name: wheels
path: dist
@@ -282,7 +284,7 @@ jobs:
- pypy
if: "startsWith(github.ref, 'refs/tags/')"
steps:
- uses: actions/download-artifact@v2
- uses: actions/download-artifact@v3
with:
name: wheels
- uses: actions/setup-python@v4

View File

@@ -1,8 +1,10 @@
repos:
- repo: https://github.com/charliermarsh/ruff-pre-commit
rev: v0.0.233
rev: v0.0.235
hooks:
- id: ruff
args: [--fix]
exclude: ^resources
- repo: https://github.com/abravalheri/validate-pyproject
rev: v0.10.1
@@ -13,6 +15,6 @@ repos:
hooks:
- id: cargo-fmt
name: cargo fmt
entry: cargo fmt --
entry: cargo +nightly fmt --
language: rust
types: [rust]

View File

@@ -46,7 +46,7 @@ For rustfmt and Clippy, we use [nightly Rust][nightly], as it is stricter than s
```shell
cargo +nightly fmt --all # Auto-formatting...
cargo +nightly clippy --fix --workspace --all-targets --all-features -- -W clippy::pedantic # Linting...
cargo +nightly clippy --fix --workspace --all-targets --all-features # Linting...
cargo test --all # Testing...
```

127
Cargo.lock generated
View File

@@ -147,6 +147,15 @@ version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "block-buffer"
version = "0.10.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "69cce20737498f97b993470a6e536b8523f0af7892a4f928cceb1ac5e52ebe7e"
dependencies = [
"generic-array",
]
[[package]]
name = "bstr"
version = "0.2.17"
@@ -427,6 +436,15 @@ version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc"
[[package]]
name = "cpufeatures"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320"
dependencies = [
"libc",
]
[[package]]
name = "crc32fast"
version = "1.3.2"
@@ -521,6 +539,16 @@ version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
[[package]]
name = "crypto-common"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
dependencies = [
"generic-array",
"typenum",
]
[[package]]
name = "cxx"
version = "1.0.85"
@@ -577,6 +605,16 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6184e33543162437515c2e2b48714794e37845ec9851711914eec9d308f6ebe8"
[[package]]
name = "digest"
version = "0.10.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f"
dependencies = [
"block-buffer",
"crypto-common",
]
[[package]]
name = "directories"
version = "4.0.1"
@@ -719,7 +757,7 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
[[package]]
name = "flake8-to-ruff"
version = "0.0.233"
version = "0.0.235"
dependencies = [
"anyhow",
"clap 4.0.32",
@@ -770,6 +808,16 @@ dependencies = [
"libc",
]
[[package]]
name = "generic-array"
version = "0.14.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9"
dependencies = [
"typenum",
"version_check",
]
[[package]]
name = "getrandom"
version = "0.2.8"
@@ -948,6 +996,8 @@ dependencies = [
"console",
"lazy_static",
"linked-hash-map",
"pest",
"pest_derive",
"serde",
"similar",
"yaml-rust",
@@ -1475,6 +1525,50 @@ version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e"
[[package]]
name = "pest"
version = "2.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4257b4a04d91f7e9e6290be5d3da4804dd5784fafde3a497d73eb2b4a158c30a"
dependencies = [
"thiserror",
"ucd-trie",
]
[[package]]
name = "pest_derive"
version = "2.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "241cda393b0cdd65e62e07e12454f1f25d57017dcc514b1514cd3c4645e3a0a6"
dependencies = [
"pest",
"pest_generator",
]
[[package]]
name = "pest_generator"
version = "2.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46b53634d8c8196302953c74d5352f33d0c512a9499bd2ce468fc9f4128fa27c"
dependencies = [
"pest",
"pest_meta",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "pest_meta"
version = "2.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ef4f1332a8d4678b41966bb4cc1d0676880e84183a1ecc3f4b69f03e99c7a51"
dependencies = [
"once_cell",
"pest",
"sha2",
]
[[package]]
name = "petgraph"
version = "0.6.2"
@@ -1837,7 +1931,7 @@ dependencies = [
[[package]]
name = "ruff"
version = "0.0.233"
version = "0.0.235"
dependencies = [
"anyhow",
"bitflags",
@@ -1892,7 +1986,7 @@ dependencies = [
[[package]]
name = "ruff_cli"
version = "0.0.233"
version = "0.0.235"
dependencies = [
"annotate-snippets 0.9.1",
"anyhow",
@@ -1929,7 +2023,7 @@ dependencies = [
[[package]]
name = "ruff_dev"
version = "0.0.233"
version = "0.0.235"
dependencies = [
"anyhow",
"clap 4.0.32",
@@ -1950,7 +2044,7 @@ dependencies = [
[[package]]
name = "ruff_macros"
version = "0.0.233"
version = "0.0.235"
dependencies = [
"once_cell",
"proc-macro2",
@@ -2219,6 +2313,17 @@ dependencies = [
"serde",
]
[[package]]
name = "sha2"
version = "0.10.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0"
dependencies = [
"cfg-if",
"cpufeatures",
"digest",
]
[[package]]
name = "shellexpand"
version = "3.0.0"
@@ -2550,6 +2655,18 @@ dependencies = [
"static_assertions",
]
[[package]]
name = "typenum"
version = "1.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba"
[[package]]
name = "ucd-trie"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e79c4d996edb816c91e4308506774452e55e95c3c9de07b6729e17e15a5ef81"
[[package]]
name = "unic-char-property"
version = "0.9.0"

View File

@@ -8,7 +8,7 @@ default-members = [".", "ruff_cli"]
[package]
name = "ruff"
version = "0.0.233"
version = "0.0.235"
authors = ["Charlie Marsh <charlie.r.marsh@gmail.com>"]
edition = "2021"
rust-version = "1.65.0"
@@ -46,7 +46,7 @@ num-traits = "0.2.15"
once_cell = { version = "1.16.0" }
path-absolutize = { version = "3.0.14", features = ["once_cell_cache", "use_unix_paths_on_wasm"] }
regex = { version = "1.6.0" }
ruff_macros = { version = "0.0.233", path = "ruff_macros" }
ruff_macros = { version = "0.0.235", path = "ruff_macros" }
rustc-hash = { version = "1.1.0" }
rustpython-ast = { features = ["unparse"], git = "https://github.com/RustPython/RustPython.git", rev = "4f38cb68e4a97aeea9eb19673803a0bd5f655383" }
rustpython-common = { git = "https://github.com/RustPython/RustPython.git", rev = "4f38cb68e4a97aeea9eb19673803a0bd5f655383" }
@@ -77,7 +77,7 @@ wasm-bindgen = { version = "0.2.83" }
is_executable = "1.0.1"
[dev-dependencies]
insta = { version = "1.19.1", features = ["yaml"] }
insta = { version = "1.19.1", features = ["yaml", "redactions"] }
test-case = { version = "2.2.2" }
wasm-bindgen-test = { version = "0.3.33" }

781
LICENSE
View File

@@ -19,3 +19,784 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
end of terms and conditions
The externally maintained libraries from which parts of the Software is derived
are:
- flake8-comprehensions, licensed as follows:
"""
MIT License
Copyright (c) 2017 Adam Johnson
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
"""
- flake8-no-pep420, licensed as follows:
"""
MIT License
Copyright (c) 2020 Adam Johnson
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
"""
- flake8-tidy-imports, licensed as follows:
"""
MIT License
Copyright (c) 2017 Adam Johnson
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
"""
- flake8-return, licensed as follows:
"""
MIT License
Copyright (c) 2019 Afonasev Evgeniy
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
"""
- flake8-2020, licensed as follows:
"""
Copyright (c) 2019 Anthony Sottile
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
"""
- pyupgrade, licensed as follows:
"""
Copyright (c) 2017 Anthony Sottile
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
"""
- flake8-blind-except, licensed as follows:
"""
The MIT License (MIT)
Copyright (c) 2014 Elijah Andrews
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
"""
- flake8-implicit-str-concat, licensed as follows:
"""
The MIT License (MIT)
Copyright (c) 2019 Dylan Turner
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
"""
- flake8-debugger, licensed as follows:
"""
MIT License
Copyright (c) 2016 Joseph Kahn
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
"""
- flake8-print, licensed as follows:
"""
MIT License
Copyright (c) 2016 Joseph Kahn
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
"""
- flake8-import-conventions, licensed as follows:
"""
MIT License
Copyright (c) 2021 João Palmeiro
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
"""
- flake8-simplify, licensed as follows:
"""
MIT License
Copyright (c) 2020 Martin Thoma
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
"""
- flake8-unused-arguments, licensed as follows:
"""
MIT License
Copyright (c) 2019 Nathan Hoad
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
"""
- pygrep-hooks, licensed as follows:
"""
Copyright (c) 2018 Anthony Sottile
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
"""
- autoflake, licensed as follows:
"""
Copyright (C) 2012-2018 Steven Myint
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
"""
- Flake8, licensed as follows:
"""
== Flake8 License (MIT) ==
Copyright (C) 2011-2013 Tarek Ziade <tarek@ziade.org>
Copyright (C) 2012-2016 Ian Cordasco <graffatcolmingov@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
"""
- flake8-bugbear, licensed as follows:
"""
The MIT License (MIT)
Copyright (c) 2016 Łukasz Langa
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
"""
- flake8-commas, licensed as follows:
"""
The MIT License (MIT)
Copyright (c) 2017 Thomas Grainger.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
Portions of this flake8-commas Software may utilize the following
copyrighted material, the use of which is hereby acknowledged.
Original flake8-commas: https://github.com/trevorcreech/flake8-commas/commit/e8563b71b1d5442e102c8734c11cb5202284293d
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
"""
- isort, licensed as follows:
"""
The MIT License (MIT)
Copyright (c) 2013 Timothy Edmund Crosley
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
"""
- pep8-naming, licensed as follows:
"""
Copyright © 2013 Florent Xicluna <florent.xicluna@gmail.com>
Licensed under the terms of the Expat License
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation files
(the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software,
and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
"""
- pycodestyle, licensed as follows:
"""
Copyright © 2006-2009 Johann C. Rocholl <johann@rocholl.net>
Copyright © 2009-2014 Florent Xicluna <florent.xicluna@gmail.com>
Copyright © 2014-2020 Ian Lee <IanLee1521@gmail.com>
Licensed under the terms of the Expat License
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation files
(the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software,
and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
"""
- pydocstyle, licensed as follows:
"""
Copyright (c) 2012 GreenSteam, <http://greensteam.dk/>
Copyright (c) 2014-2020 Amir Rachum, <http://amir.rachum.com/>
Copyright (c) 2020 Sambhav Kothari, <https://github.com/samj1912>
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
"""
- Pyflakes, licensed as follows:
"""
Copyright 2005-2011 Divmod, Inc.
Copyright 2013-2014 Florent Xicluna
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
"""
- flake8-use-pathlib, licensed as follows:
"""
MIT License
Copyright (c) 2021 Rodolphe Pelloux-Prayer
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
"""
- RustPython, licensed as follows:
"""
MIT License
Copyright (c) 2020 RustPython Team
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
"""
- flake8-annotations, licensed as follows:
"""
MIT License
Copyright (c) 2019 - Present S. Co1
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
"""
- flake8-type-checking, licensed as follows:
"""
Copyright (c) 2021, Sondre Lillebø Gundersen
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of pytest-{{ cookiecutter.plugin_name }} nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""
- flake8-bandit, licensed as follows:
"""
Copyright (c) 2017 Tyler Wince
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
"""
- flake8-eradicate, licensed as follows:
"""
MIT License
Copyright (c) 2018 Nikita Sobolev
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
"""
- flake8-quotes, licensed as follows:
"""
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
"""

View File

@@ -67,6 +67,7 @@ Ruff is extremely actively developed and used in major open-source projects like
- [Home Assistant](https://github.com/home-assistant/core)
- [Cryptography (PyCA)](https://github.com/pyca/cryptography)
- [cibuildwheel (PyPA)](https://github.com/pypa/cibuildwheel)
- [Babel](https://github.com/python-babel/babel)
Read the [launch blog post](https://notes.crmarsh.com/python-tooling-could-be-much-much-faster).
@@ -143,7 +144,7 @@ developer of [Zulip](https://github.com/zulip/zulip):
1. [flake8-commas (COM)](#flake8-commas-com)
1. [flake8-no-pep420 (INP)](#flake8-no-pep420-inp)
1. [flake8-executable (EXE)](#flake8-executable-exe)
1. [flake8-type-checking (TYP)](#flake8-type-checking-typ)
1. [flake8-type-checking (TCH)](#flake8-type-checking-tch)
1. [tryceratops (TRY)](#tryceratops-try)
1. [flake8-use-pathlib (PTH)](#flake8-use-pathlib-pth)
1. [Ruff-specific rules (RUF)](#ruff-specific-rules-ruf)<!-- End auto-generated table of contents. -->
@@ -212,7 +213,7 @@ Ruff also works with [pre-commit](https://pre-commit.com):
```yaml
- repo: https://github.com/charliermarsh/ruff-pre-commit
# Ruff version.
rev: 'v0.0.233'
rev: 'v0.0.235'
hooks:
- id: ruff
```
@@ -853,7 +854,7 @@ For more, see [flake8-bugbear](https://pypi.org/project/flake8-bugbear/) on PyPI
| B004 | unreliable-callable-check | Using `hasattr(x, '__call__')` to test if x is callable is unreliable. Use `callable(x)` for consistent results. | |
| B005 | strip-with-multi-characters | Using `.strip()` with multi-character strings is misleading the reader | |
| B006 | mutable-argument-default | Do not use mutable data structures for argument defaults | |
| B007 | unused-loop-control-variable | Loop control variable `{name}` not used within the loop body | 🛠 |
| B007 | unused-loop-control-variable | Loop control variable `{name}` not used within loop body | |
| B008 | function-call-argument-default | Do not perform function call `{name}` in argument defaults | |
| B009 | get-attr-with-constant | Do not call `getattr` with a constant attribute value. It is not any safer than normal property access. | 🛠 |
| B010 | set-attr-with-constant | Do not call `setattr` with a constant attribute value. It is not any safer than normal property access. | 🛠 |
@@ -1196,13 +1197,17 @@ For more, see [flake8-executable](https://pypi.org/project/flake8-executable/) o
| EXE004 | shebang-whitespace | Avoid whitespace before shebang | 🛠 |
| EXE005 | shebang-newline | Shebang should be at the beginning of the file | |
### flake8-type-checking (TYP)
### flake8-type-checking (TCH)
For more, see [flake8-type-checking](https://pypi.org/project/flake8-type-checking/) on PyPI.
| Code | Name | Message | Fix |
| ---- | ---- | ------- | --- |
| TYP005 | empty-type-checking-block | Found empty type-checking block | |
| TCH001 | typing-only-first-party-import | Move application import `{}` into a type-checking block | |
| TCH002 | typing-only-third-party-import | Move third-party import `{}` into a type-checking block | |
| TCH003 | typing-only-standard-library-import | Move standard library import `{}` into a type-checking block | |
| TCH004 | runtime-import-in-type-checking-block | Move import `{}` out of type-checking block. Import is used for more than type hinting. | |
| TCH005 | empty-type-checking-block | Found empty type-checking block | |
### tryceratops (TRY)
@@ -1692,7 +1697,7 @@ After installing `ruff` and `nbqa`, you can run Ruff over a notebook like so:
Untitled.ipynb:cell_1:2:5: F841 Local variable `x` is assigned to but never used
Untitled.ipynb:cell_2:1:1: E402 Module level import not at top of file
Untitled.ipynb:cell_2:1:8: F401 `os` imported but unused
Found 3 error(s).
Found 3 errors.
1 potentially fixable with the --fix option.
```
@@ -1728,6 +1733,25 @@ matter how they're provided, which avoids accidental incompatibilities and simpl
Run `ruff /path/to/code.py --show-settings` to view the resolved settings for a given file.
### Ruff tried to fix something, but it broke my code. What should I do?
Ruff's autofix is a best-effort mechanism. Given the dynamic nature of Python, it's difficult to
have _complete_ certainty when making changes to code, even for the seemingly trivial fixes.
In the future, Ruff will support enabling autofix behavior based on the safety of the patch.
In the meantime, if you find that the autofix is too aggressive, you can disable it on a per-rule or
per-category basis using the [`unfixable`](#unfixable) mechanic. For example, to disable autofix
for some possibly-unsafe rules, you could add the following to your `pyproject.toml`:
```toml
[tool.ruff]
unfixable = ["B", "SIM", "TRY", "RUF"]
```
If you find a case where Ruff's autofix breaks your code, please file an Issue!
## Contributing
Contributions are welcome and hugely appreciated. To get started, check out the
@@ -2677,6 +2701,25 @@ extend-immutable-calls = ["fastapi.Depends", "fastapi.Query"]
---
### `flake8-builtins`
#### [`builtins-ignorelist`](#builtins-ignorelist)
Ignore list of builtins.
**Default value**: `[]`
**Type**: `Vec<String>`
**Example usage**:
```toml
[tool.ruff.flake8-builtins]
builtins-ignorelist = ["id"]
```
---
### `flake8-errmsg`
#### [`max-string-length`](#max-string-length)

View File

@@ -771,7 +771,7 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
[[package]]
name = "flake8_to_ruff"
version = "0.0.233"
version = "0.0.235"
dependencies = [
"anyhow",
"clap",
@@ -1975,7 +1975,7 @@ dependencies = [
[[package]]
name = "ruff"
version = "0.0.233"
version = "0.0.235"
dependencies = [
"anyhow",
"bincode",

View File

@@ -1,6 +1,6 @@
[package]
name = "flake8-to-ruff"
version = "0.0.233"
version = "0.0.235"
edition = "2021"
[dependencies]

View File

@@ -1,4 +1,6 @@
//! Utility to generate Ruff's `pyproject.toml` section from a Flake8 INI file.
#![forbid(unsafe_code)]
#![warn(clippy::pedantic)]
#![allow(
clippy::collapsible_else_if,
clippy::collapsible_if,
@@ -11,7 +13,6 @@
clippy::similar_names,
clippy::too_many_lines
)]
#![forbid(unsafe_code)]
use std::path::PathBuf;

View File

@@ -1,21 +0,0 @@
MIT License
Copyright (c) 2016 Joseph Kahn
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -1,21 +0,0 @@
MIT License
Copyright (c) 2020 Martin Thoma
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -1,19 +0,0 @@
Copyright (C) 2012-2018 Steven Myint
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -1,22 +0,0 @@
== Flake8 License (MIT) ==
Copyright (C) 2011-2013 Tarek Ziade <tarek@ziade.org>
Copyright (C) 2012-2016 Ian Cordasco <graffatcolmingov@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -1,21 +0,0 @@
The MIT License (MIT)
Copyright (c) 2016 Łukasz Langa
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -1,45 +0,0 @@
The MIT License (MIT)
Copyright (c) 2017 Thomas Grainger.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
Portions of this flake8-commas Software may utilize the following
copyrighted material, the use of which is hereby acknowledged.
Original flake8-commas: https://github.com/trevorcreech/flake8-commas/commit/e8563b71b1d5442e102c8734c11cb5202284293d
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@@ -1,21 +0,0 @@
The MIT License (MIT)
Copyright (c) 2013 Timothy Edmund Crosley
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@@ -1,23 +0,0 @@
Copyright © 2013 Florent Xicluna <florent.xicluna@gmail.com>
Licensed under the terms of the Expat License
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation files
(the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software,
and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -1,25 +0,0 @@
Copyright © 2006-2009 Johann C. Rocholl <johann@rocholl.net>
Copyright © 2009-2014 Florent Xicluna <florent.xicluna@gmail.com>
Copyright © 2014-2020 Ian Lee <IanLee1521@gmail.com>
Licensed under the terms of the Expat License
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation files
(the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software,
and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -1,23 +0,0 @@
Copyright (c) 2012 GreenSteam, <http://greensteam.dk/>
Copyright (c) 2014-2020 Amir Rachum, <http://amir.rachum.com/>
Copyright (c) 2020 Sambhav Kothari, <https://github.com/samj1912>
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -1,21 +0,0 @@
Copyright 2005-2011 Divmod, Inc.
Copyright 2013-2014 Florent Xicluna
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@@ -1,22 +0,0 @@
MIT License
Copyright (c) 2021 Rodolphe Pelloux-Prayer
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -1,21 +0,0 @@
MIT License
Copyright (c) 2020 RustPython Team
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -1,21 +0,0 @@
MIT License
Copyright (c) 2017 Adam Johnson
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -1,21 +0,0 @@
MIT License
Copyright (c) 2020 Adam Johnson
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -1,21 +0,0 @@
MIT License
Copyright (c) 2017 Adam Johnson
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -1,21 +0,0 @@
MIT License
Copyright (c) 2019 Afonasev Evgeniy
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -1,19 +0,0 @@
Copyright (c) 2019 Anthony Sottile
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@@ -1,19 +0,0 @@
Copyright (c) 2017 Anthony Sottile
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@@ -1,20 +0,0 @@
The MIT License (MIT)
Copyright (c) 2014 Elijah Andrews
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@@ -1,21 +0,0 @@
The MIT License (MIT)
Copyright (c) 2019 Dylan Turner
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@@ -1,21 +0,0 @@
MIT License
Copyright (c) 2016 Joseph Kahn
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -1,21 +0,0 @@
MIT License
Copyright (c) 2021 João Palmeiro
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -1,21 +0,0 @@
MIT License
Copyright (c) 2019 Nathan Hoad
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -1,19 +0,0 @@
Copyright (c) 2018 Anthony Sottile
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@@ -1,21 +0,0 @@
MIT License
Copyright (c) 2019 - Present S. Co1
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -1,19 +0,0 @@
Copyright (c) 2017 Tyler Wince
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@@ -1,21 +0,0 @@
MIT License
Copyright (c) 2018 Nikita Sobolev
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -1,17 +0,0 @@
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@@ -7,7 +7,7 @@ build-backend = "maturin"
[project]
name = "ruff"
version = "0.0.233"
version = "0.0.235"
description = "An extremely fast Python linter, written in Rust."
authors = [
{ name = "Charlie Marsh", email = "charlie.r.marsh@gmail.com" },

View File

@@ -29,3 +29,19 @@ def strange_generator():
for i, (j, (k, l)) in strange_generator(): # i, k not used
print(j, l)
FMT = "{foo} {bar}"
for foo, bar in [(1, 2)]:
if foo:
print(FMT.format(**locals()))
for foo, bar in [(1, 2)]:
if foo:
print(FMT.format(**globals()))
for foo, bar in [(1, 2)]:
if foo:
print(FMT.format(**vars()))
for foo, bar in [(1, 2)]:
print(FMT.format(foo=foo, bar=eval('bar')))

View File

@@ -0,0 +1,28 @@
"""Tests to determine first-party import classification.
For typing-only import detection tests, see `TCH002.py`.
"""
def f():
import TYP001
x: TYP001
def f():
import TYP001
print(TYP001)
def f():
from . import TYP001
x: TYP001
def f():
from . import TYP001
print(TYP001)

View File

@@ -0,0 +1,148 @@
"""Tests to determine accurate detection of typing-only imports."""
def f():
import pandas as pd # TCH002
x: pd.DataFrame
def f():
from pandas import DataFrame # TCH002
x: DataFrame
def f():
from pandas import DataFrame as df # TCH002
x: df
def f():
import pandas as pd # TCH002
x: pd.DataFrame = 1
def f():
from pandas import DataFrame # TCH002
x: DataFrame = 2
def f():
from pandas import DataFrame as df # TCH002
x: df = 3
def f():
import pandas as pd # TCH002
x: "pd.DataFrame" = 1
def f():
import pandas as pd
x = dict["pd.DataFrame", "pd.DataFrame"] # TCH002
def f():
import pandas as pd
print(pd)
def f():
from pandas import DataFrame
print(DataFrame)
def f():
from pandas import DataFrame
def f():
print(DataFrame)
def f():
from typing import Dict, Any
def example() -> Any:
return 1
x: Dict[int] = 20
def f():
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from typing import Dict
x: Dict[int] = 20
def f():
from pathlib import Path
class ImportVisitor(ast.NodeTransformer):
def __init__(self, cwd: Path) -> None:
self.cwd = cwd
origin = Path(spec.origin)
class ExampleClass:
def __init__(self):
self.cwd = Path(pandas.getcwd())
def f():
import pandas
class Migration:
enum = pandas
def f():
import pandas
class Migration:
enum = pandas.EnumClass
def f():
from typing import TYPE_CHECKING
from pandas import y
if TYPE_CHECKING:
_type = x
else:
_type = y
def f():
from typing import TYPE_CHECKING
from pandas import y
if TYPE_CHECKING:
_type = x
elif True:
_type = y
def f():
from typing import cast
import pandas as pd
x = cast(pd.DataFrame, 2)
def f():
import pandas as pd
x = dict[pd.DataFrame, pd.DataFrame]

View File

@@ -0,0 +1,16 @@
"""Tests to determine standard library import classification.
For typing-only import detection tests, see `TCH002.py`.
"""
def f():
import os
x: os
def f():
import os
print(os)

View File

@@ -0,0 +1,5 @@
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from datetime import datetime
x = datetime

View File

@@ -0,0 +1,8 @@
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from datetime import date
def example():
return date()

View File

@@ -0,0 +1,6 @@
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from typing import Any
CustomType = Any

View File

@@ -0,0 +1,11 @@
from typing import TYPE_CHECKING, Type
if TYPE_CHECKING:
from typing import Any
def example(*args: Any, **kwargs: Any):
return
my_type: Type[Any] | Any

View File

@@ -0,0 +1,8 @@
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from typing import List, Sequence, Set
def example(a: List[int], /, b: Sequence[int], *, c: Set[int]):
return

View File

@@ -0,0 +1,10 @@
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from pandas import DataFrame
def example():
from pandas import DataFrame
x = DataFrame

View File

@@ -0,0 +1,10 @@
from __future__ import annotations
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from typing import AsyncIterator, List
class Example:
async def example(self) -> AsyncIterator[List[str]]:
yield 0

View File

@@ -0,0 +1,7 @@
from typing import TYPE_CHECKING
from weakref import WeakKeyDictionary
if TYPE_CHECKING:
from typing import Any
d = WeakKeyDictionary["Any", "Any"]()

View File

@@ -1,7 +1,7 @@
from typing import TYPE_CHECKING, List
if TYPE_CHECKING:
pass # TYP005
pass # TCH005
def example():

View File

@@ -0,0 +1,3 @@
from pathlib import Path
(Path("") / "").open()

View File

@@ -94,7 +94,7 @@ def incorrect_MemoryError(some_arg):
# not multiline is on purpose for fix
raise MemoryError(
"..."
)
)
def incorrect_NameError(some_arg):
@@ -294,3 +294,39 @@ def multiple_ifs(some_args):
raise ValueError("...") # this is ok if we don't simplify
else:
pass
def early_return():
if isinstance(this, some_type):
if x in this:
return
raise ValueError(f"{this} has a problem") # this is ok
def early_break():
for x in this:
if isinstance(this, some_type):
if x in this:
break
raise ValueError(f"{this} has a problem") # this is ok
def early_continue():
for x in this:
if isinstance(this, some_type):
if x in this:
continue
raise ValueError(f"{this} has a problem") # this is ok
def early_return_else():
if isinstance(this, some_type):
pass
else:
if x in this:
return
raise ValueError(f"{this} has a problem") # this is ok

View File

@@ -1,27 +1,32 @@
"""
Violation:
Reraise without using 'from'
"""
class MyException(Exception):
pass
class MainFunctionFailed(Exception):
pass
def process():
raise MyException
def bad():
def func():
try:
process()
except MyException:
raise MainFunctionFailed()
a = 1
except Exception:
raise MyException()
def func():
try:
a = 1
except Exception:
if True:
raise MainFunctionFailed()
raise MyException()
def good():
try:
process()
except MyException as ex:
raise MainFunctionFailed() from ex
a = 1
except MyException as e:
raise e # This is verbose violation, shouldn't trigger no cause
except Exception:
raise # Just re-raising don't need 'from'

View File

@@ -16,7 +16,7 @@ resources/test/project/examples/docs/docs/file.py:1:1: I001 Import block is un-s
resources/test/project/examples/docs/docs/file.py:8:5: F841 Local variable `x` is assigned to but never used
resources/test/project/project/file.py:1:8: F401 `os` imported but unused
resources/test/project/project/import_file.py:1:1: I001 Import block is un-sorted or un-formatted
Found 7 error(s).
Found 7 errors.
7 potentially fixable with the --fix option.
```
@@ -31,7 +31,7 @@ examples/docs/docs/file.py:1:1: I001 Import block is un-sorted or un-formatted
examples/docs/docs/file.py:8:5: F841 Local variable `x` is assigned to but never used
project/file.py:1:8: F401 `os` imported but unused
project/import_file.py:1:1: I001 Import block is un-sorted or un-formatted
Found 7 error(s).
Found 7 errors.
7 potentially fixable with the --fix option.
```
@@ -42,7 +42,7 @@ files:
∴ (cd resources/test/project/examples/docs && cargo run .)
docs/file.py:1:1: I001 Import block is un-sorted or un-formatted
docs/file.py:8:5: F841 Local variable `x` is assigned to but never used
Found 2 error(s).
Found 2 errors.
2 potentially fixable with the --fix option.
```
@@ -60,7 +60,7 @@ resources/test/project/examples/docs/docs/file.py:3:8: F401 `numpy` imported but
resources/test/project/examples/docs/docs/file.py:4:27: F401 `docs.concepts.file` imported but unused
resources/test/project/examples/excluded/script.py:1:8: F401 `os` imported but unused
resources/test/project/project/file.py:1:8: F401 `os` imported but unused
Found 9 error(s).
Found 9 errors.
9 potentially fixable with the --fix option.
```
@@ -73,7 +73,7 @@ docs/docs/concepts/file.py:5:5: F841 Local variable `x` is assigned to but never
docs/docs/file.py:1:1: I001 Import block is un-sorted or un-formatted
docs/docs/file.py:8:5: F841 Local variable `x` is assigned to but never used
excluded/script.py:5:5: F841 Local variable `x` is assigned to but never used
Found 4 error(s).
Found 4 errors.
4 potentially fixable with the --fix option.
```
@@ -82,7 +82,7 @@ Passing an excluded directory directly should report errors in the contained fil
```
∴ cargo run resources/test/project/examples/excluded/
resources/test/project/examples/excluded/script.py:1:8: F401 `os` imported but unused
Found 1 error(s).
Found 1 error.
1 potentially fixable with the --fix option.
```

View File

@@ -1138,10 +1138,6 @@
"PythonVersion": {
"type": "string",
"enum": [
"py33",
"py34",
"py35",
"py36",
"py37",
"py38",
"py39",
@@ -1764,6 +1760,14 @@
"T20",
"T201",
"T203",
"TCH",
"TCH0",
"TCH00",
"TCH001",
"TCH002",
"TCH003",
"TCH004",
"TCH005",
"TID",
"TID2",
"TID25",
@@ -1781,10 +1785,6 @@
"TRY30",
"TRY300",
"TRY301",
"TYP",
"TYP0",
"TYP00",
"TYP005",
"UP",
"UP0",
"UP00",

View File

@@ -1,6 +1,6 @@
[package]
name = "ruff_cli"
version = "0.0.233"
version = "0.0.235"
authors = ["Charlie Marsh <charlie.r.marsh@gmail.com>"]
edition = "2021"
rust-version = "1.65.0"

View File

@@ -120,7 +120,7 @@ pub fn run(
location: Location::default(),
end_location: Location::default(),
fix: None,
filename: path.to_string_lossy().to_string(),
filename: format!("{}", path.display()),
source: None,
}])
} else {

View File

@@ -2,6 +2,8 @@
//! to automatically update the `ruff --help` output in the `README.md`.
//!
//! For the actual Ruff library, see [`ruff`].
#![forbid(unsafe_code)]
#![warn(clippy::pedantic)]
#![allow(clippy::must_use_candidate, dead_code)]
mod cli;

View File

@@ -1,10 +1,11 @@
#![forbid(unsafe_code)]
#![warn(clippy::pedantic)]
#![allow(
clippy::match_same_arms,
clippy::missing_errors_doc,
clippy::module_name_repetitions,
clippy::too_many_lines
)]
#![forbid(unsafe_code)]
use std::io::{self};
use std::path::{Path, PathBuf};
@@ -88,7 +89,7 @@ fn resolve(
}
}
pub fn main() -> Result<ExitCode> {
fn inner_main() -> Result<ExitCode> {
// Extract command-line arguments.
let (cli, overrides) = Cli::parse().partition();
@@ -200,7 +201,7 @@ quoting the executed command, along with the relevant file contents and `pyproje
if cache {
// `--no-cache` doesn't respect code changes, and so is often confusing during
// development.
warn_user_once!("debug build without --no-cache.");
warn_user_once!("Detected debug build without --no-cache.");
}
let printer = Printer::new(&format, &log_level, &autofix, &violations);
@@ -319,3 +320,14 @@ quoting the executed command, along with the relevant file contents and `pyproje
Ok(ExitCode::SUCCESS)
}
#[must_use]
pub fn main() -> ExitCode {
match inner_main() {
Ok(code) => code,
Err(err) => {
eprintln!("{}{} {err:?}", "error".red().bold(), ":".bold());
ExitCode::FAILURE
}
}
}

View File

@@ -96,12 +96,14 @@ impl<'a> Printer<'a> {
let remaining = diagnostics.messages.len();
let total = fixed + remaining;
if fixed > 0 {
let s = if total == 1 { "" } else { "s" };
writeln!(
stdout,
"Found {total} error(s) ({fixed} fixed, {remaining} remaining)."
"Found {total} error{s} ({fixed} fixed, {remaining} remaining)."
)?;
} else if remaining > 0 {
writeln!(stdout, "Found {remaining} error(s).")?;
let s = if remaining == 1 { "" } else { "s" };
writeln!(stdout, "Found {remaining} error{s}.")?;
}
if !matches!(self.autofix, fix::FixMode::Apply) {
@@ -121,10 +123,11 @@ impl<'a> Printer<'a> {
Violations::Hide => {
let fixed = diagnostics.fixed;
if fixed > 0 {
let s = if fixed == 1 { "" } else { "s" };
if matches!(self.autofix, fix::FixMode::Apply) {
writeln!(stdout, "Fixed {fixed} error(s).")?;
writeln!(stdout, "Fixed {fixed} error{s}.")?;
} else if matches!(self.autofix, fix::FixMode::Diff) {
writeln!(stdout, "Would fix {fixed} error(s).")?;
writeln!(stdout, "Would fix {fixed} error{s}.")?;
}
}
}
@@ -339,8 +342,13 @@ impl<'a> Printer<'a> {
}
if self.log_level >= &LogLevel::Default {
let s = if diagnostics.messages.len() == 1 {
""
} else {
"s"
};
notify_user!(
"Found {} error(s). Watching for file changes.",
"Found {} error{s}. Watching for file changes.",
diagnostics.messages.len()
);
}

View File

@@ -1,9 +1,12 @@
#![cfg(not(target_family = "wasm"))]
#[cfg(unix)]
use std::path::Path;
use std::str;
use anyhow::Result;
use assert_cmd::Command;
#[cfg(unix)]
use path_absolutize::path_dedot;
const BIN_NAME: &str = "ruff";
@@ -28,7 +31,7 @@ fn test_stdin_error() -> Result<()> {
.failure();
assert_eq!(
str::from_utf8(&output.get_output().stdout)?,
"-:1:8: F401 `os` imported but unused\nFound 1 error(s).\n1 potentially fixable with the \
"-:1:8: F401 `os` imported but unused\nFound 1 error.\n1 potentially fixable with the \
--fix option.\n"
);
Ok(())
@@ -44,12 +47,13 @@ fn test_stdin_filename() -> Result<()> {
.failure();
assert_eq!(
str::from_utf8(&output.get_output().stdout)?,
"F401.py:1:8: F401 `os` imported but unused\nFound 1 error(s).\n1 potentially fixable \
with the --fix option.\n"
"F401.py:1:8: F401 `os` imported but unused\nFound 1 error.\n1 potentially fixable with \
the --fix option.\n"
);
Ok(())
}
#[cfg(unix)]
#[test]
fn test_stdin_json() -> Result<()> {
let mut cmd = Command::cargo_bin(BIN_NAME)?;
@@ -58,6 +62,11 @@ fn test_stdin_json() -> Result<()> {
.write_stdin("import os\n")
.assert()
.failure();
let directory = path_dedot::CWD.to_str().unwrap();
let binding = Path::new(directory).join("F401.py");
let file_path = binding.display();
assert_eq!(
str::from_utf8(&output.get_output().stdout)?,
format!(
@@ -85,11 +94,10 @@ fn test_stdin_json() -> Result<()> {
"row": 1,
"column": 10
}},
"filename": "{}/F401.py"
"filename": "{file_path}"
}}
]
"#,
path_dedot::CWD.to_str().unwrap()
"#
)
);
Ok(())

View File

@@ -1,6 +1,6 @@
[package]
name = "ruff_dev"
version = "0.0.233"
version = "0.0.235"
edition = "2021"
[dependencies]

View File

@@ -1,6 +1,8 @@
//! This crate implements an internal CLI for developers of Ruff.
//!
//! Within the ruff repository you can run it with `cargo dev`.
#![forbid(unsafe_code)]
#![warn(clippy::pedantic)]
#![allow(
clippy::collapsible_else_if,
clippy::collapsible_if,
@@ -13,7 +15,6 @@
clippy::similar_names,
clippy::too_many_lines
)]
#![forbid(unsafe_code)]
mod generate_all;
mod generate_cli_help;

View File

@@ -1,6 +1,6 @@
[package]
name = "ruff_macros"
version = "0.0.233"
version = "0.0.235"
edition = "2021"
[lib]

View File

@@ -1,4 +1,6 @@
//! This crate implements internal macros for the `ruff` library.
#![forbid(unsafe_code)]
#![warn(clippy::pedantic)]
#![allow(
clippy::collapsible_else_if,
clippy::collapsible_if,
@@ -11,7 +13,6 @@
clippy::similar_names,
clippy::too_many_lines
)]
#![forbid(unsafe_code)]
use proc_macro::TokenStream;
use syn::{parse_macro_input, DeriveInput, ItemFn};

View File

@@ -1,8 +1,7 @@
import os
import re
from pathlib import Path
ROOT_DIR = Path(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
ROOT_DIR = Path(__file__).resolve().parent.parent
def dir_name(linter_name: str) -> str:
@@ -15,4 +14,4 @@ def pascal_case(linter_name: str) -> str:
def get_indent(line: str) -> str:
return re.match(r"^\s*", line).group() # pyright: ignore[reportOptionalMemberAccess]
return re.match(r"^\s*", line).group() # type: ignore[union-attr]

View File

@@ -10,15 +10,14 @@ Example usage:
"""
import argparse
import os
from _utils import ROOT_DIR, dir_name, get_indent, pascal_case
def main(*, plugin: str, url: str, prefix_code: str) -> None:
"""Generate boilerplate for a new plugin."""
# Create the test fixture folder.
os.makedirs(
ROOT_DIR / "resources/test/fixtures" / dir_name(plugin),
(ROOT_DIR / "resources/test/fixtures" / dir_name(plugin)).mkdir(
exist_ok=True,
)
@@ -41,7 +40,7 @@ mod tests {
use crate::registry::Rule;
use crate::linter::test_path;
use crate::settings;
use crate::{assert_yaml_snapshot, settings};
fn rules(rule_code: Rule, path: &Path) -> Result<()> {
let snapshot = format!("{}_{}", rule_code.as_ref(), path.to_string_lossy());
@@ -51,12 +50,12 @@ mod tests {
.as_path(),
&settings::Settings::for_rule(rule_code),
)?;
insta::assert_yaml_snapshot!(snapshot, diagnostics);
assert_yaml_snapshot!(snapshot, diagnostics);
Ok(())
}
}
"""
% dir_name(plugin)
% dir_name(plugin),
)
# Create a subdirectory for rules and create a `mod.rs` placeholder
@@ -84,7 +83,7 @@ mod tests {
fp.write(f"{indent}// {plugin}")
fp.write("\n")
elif line.strip() == '/// Ruff-specific rules':
elif line.strip() == "/// Ruff-specific rules":
fp.write(f"/// [{plugin}]({url})\n")
fp.write(f'{indent}#[prefix = "{prefix_code}"]\n')
fp.write(f"{indent}{pascal_case(plugin)},")

View File

@@ -16,12 +16,17 @@ from _utils import ROOT_DIR, dir_name, get_indent
def snake_case(name: str) -> str:
"""Convert from PascalCase to snake_case."""
return "".join(f"_{word.lower()}" if word.isupper() else word for word in name).lstrip("_")
return "".join(
f"_{word.lower()}" if word.isupper() else word for word in name
).lstrip("_")
def main(*, name: str, code: str, linter: str) -> None:
"""Generate boilerplate for a new rule."""
# Create a test fixture.
with (ROOT_DIR / "resources/test/fixtures" / dir_name(linter) / f"{code}.py").open("a"):
with (ROOT_DIR / "resources/test/fixtures" / dir_name(linter) / f"{code}.py").open(
"a",
):
pass
plugin_module = ROOT_DIR / "src/rules" / dir_name(linter)
@@ -35,13 +40,15 @@ def main(*, name: str, code: str, linter: str) -> None:
for line in content.splitlines():
if line.strip() == "fn rules(rule_code: Rule, path: &Path) -> Result<()> {":
indent = get_indent(line)
fp.write(f'{indent}#[test_case(Rule::{name}, Path::new("{code}.py"); "{code}")]')
fp.write(
f'{indent}#[test_case(Rule::{name}, Path::new("{code}.py"); "{code}")]',
)
fp.write("\n")
fp.write(line)
fp.write("\n")
# Add the exports
# Add the exports
rules_dir = plugin_module / "rules"
rules_mod = rules_dir / "mod.rs"
@@ -83,14 +90,14 @@ impl Violation for %s {
}
}
"""
% (name, name)
% (name, name),
)
fp.write("\n")
fp.write(
f"""
/// {code}
pub fn {rule_name_snake}(checker: &mut Checker) {{}}
"""
""",
)
fp.write("\n")

View File

@@ -1,8 +1,10 @@
[tool.ruff]
select = ["ALL"]
ignore = [
"S101", # assert-used
"PLR2004", # magic-value-comparison
"E501", # line-too-long
"INP001", # implicit-namespace-package
"PLR2004", # magic-value-comparison
"S101", # assert-used
]
[tool.ruff.pydocstyle]

View File

@@ -0,0 +1,18 @@
/// Platform-independent snapshot assertion
#[macro_export]
macro_rules! assert_yaml_snapshot {
( $($args: expr),+) => {
let line_sep = if cfg!(windows) { "\r\n" } else { "\n" };
// adjust snapshot file for platform
let mut settings = insta::Settings::clone_current();
settings.add_redaction("[].fix.content", insta::dynamic_redaction(move |value, _path| {
insta::internals::Content::Seq(
value.as_str().unwrap().split(line_sep).map(|line| line.into()).collect()
)
}));
settings.bind(|| {
insta::assert_yaml_snapshot!($($args),+);
});
};
}

View File

@@ -40,19 +40,22 @@ pub fn unparse_stmt(stmt: &Stmt, stylist: &Stylist) -> String {
generator.generate()
}
fn collect_call_path_inner<'a>(expr: &'a Expr, parts: &mut CallPath<'a>) {
fn collect_call_path_inner<'a>(expr: &'a Expr, parts: &mut CallPath<'a>) -> bool {
match &expr.node {
ExprKind::Call { func, .. } => {
collect_call_path_inner(func, parts);
}
ExprKind::Call { func, .. } => collect_call_path_inner(func, parts),
ExprKind::Attribute { value, attr, .. } => {
collect_call_path_inner(value, parts);
parts.push(attr);
if collect_call_path_inner(value, parts) {
parts.push(attr);
true
} else {
false
}
}
ExprKind::Name { id, .. } => {
parts.push(id);
true
}
_ => {}
_ => false,
}
}
@@ -236,6 +239,186 @@ where
}
}
pub fn any_over_stmt<F>(stmt: &Stmt, func: &F) -> bool
where
F: Fn(&Expr) -> bool,
{
match &stmt.node {
StmtKind::FunctionDef {
args,
body,
decorator_list,
returns,
..
}
| StmtKind::AsyncFunctionDef {
args,
body,
decorator_list,
returns,
..
} => {
args.defaults.iter().any(|expr| any_over_expr(expr, func))
|| args
.kw_defaults
.iter()
.any(|expr| any_over_expr(expr, func))
|| args.args.iter().any(|arg| {
arg.node
.annotation
.as_ref()
.map_or(false, |expr| any_over_expr(expr, func))
})
|| args.kwonlyargs.iter().any(|arg| {
arg.node
.annotation
.as_ref()
.map_or(false, |expr| any_over_expr(expr, func))
})
|| args.posonlyargs.iter().any(|arg| {
arg.node
.annotation
.as_ref()
.map_or(false, |expr| any_over_expr(expr, func))
})
|| args.vararg.as_ref().map_or(false, |arg| {
arg.node
.annotation
.as_ref()
.map_or(false, |expr| any_over_expr(expr, func))
})
|| args.kwarg.as_ref().map_or(false, |arg| {
arg.node
.annotation
.as_ref()
.map_or(false, |expr| any_over_expr(expr, func))
})
|| body.iter().any(|stmt| any_over_stmt(stmt, func))
|| decorator_list.iter().any(|expr| any_over_expr(expr, func))
|| returns
.as_ref()
.map_or(false, |value| any_over_expr(value, func))
}
StmtKind::ClassDef {
bases,
keywords,
body,
decorator_list,
..
} => {
bases.iter().any(|expr| any_over_expr(expr, func))
|| keywords
.iter()
.any(|keyword| any_over_expr(&keyword.node.value, func))
|| body.iter().any(|stmt| any_over_stmt(stmt, func))
|| decorator_list.iter().any(|expr| any_over_expr(expr, func))
}
StmtKind::Return { value } => value
.as_ref()
.map_or(false, |value| any_over_expr(value, func)),
StmtKind::Delete { targets } => targets.iter().any(|expr| any_over_expr(expr, func)),
StmtKind::Assign { targets, value, .. } => {
targets.iter().any(|expr| any_over_expr(expr, func)) || any_over_expr(value, func)
}
StmtKind::AugAssign { target, value, .. } => {
any_over_expr(target, func) || any_over_expr(value, func)
}
StmtKind::AnnAssign {
target,
annotation,
value,
..
} => {
any_over_expr(target, func)
|| any_over_expr(annotation, func)
|| value
.as_ref()
.map_or(false, |value| any_over_expr(value, func))
}
StmtKind::For {
target,
iter,
body,
orelse,
..
}
| StmtKind::AsyncFor {
target,
iter,
body,
orelse,
..
} => {
any_over_expr(target, func)
|| any_over_expr(iter, func)
|| any_over_body(body, func)
|| any_over_body(orelse, func)
}
StmtKind::While { test, body, orelse } => {
any_over_expr(test, func) || any_over_body(body, func) || any_over_body(orelse, func)
}
StmtKind::If { test, body, orelse } => {
any_over_expr(test, func) || any_over_body(body, func) || any_over_body(orelse, func)
}
StmtKind::With { items, body, .. } | StmtKind::AsyncWith { items, body, .. } => {
items.iter().any(|withitem| {
any_over_expr(&withitem.context_expr, func)
|| withitem
.optional_vars
.as_ref()
.map_or(false, |expr| any_over_expr(expr, func))
}) || any_over_body(body, func)
}
StmtKind::Raise { exc, cause } => {
exc.as_ref()
.map_or(false, |value| any_over_expr(value, func))
|| cause
.as_ref()
.map_or(false, |value| any_over_expr(value, func))
}
StmtKind::Try {
body,
handlers,
orelse,
finalbody,
} => {
any_over_body(body, func)
|| handlers.iter().any(|handler| {
let ExcepthandlerKind::ExceptHandler { type_, body, .. } = &handler.node;
type_
.as_ref()
.map_or(false, |expr| any_over_expr(expr, func))
|| any_over_body(body, func)
})
|| any_over_body(orelse, func)
|| any_over_body(finalbody, func)
}
StmtKind::Assert { test, msg } => {
any_over_expr(test, func)
|| msg
.as_ref()
.map_or(false, |value| any_over_expr(value, func))
}
// TODO(charlie): Handle match statements.
StmtKind::Match { .. } => false,
StmtKind::Import { .. } => false,
StmtKind::ImportFrom { .. } => false,
StmtKind::Global { .. } => false,
StmtKind::Nonlocal { .. } => false,
StmtKind::Expr { value } => any_over_expr(value, func),
StmtKind::Pass => false,
StmtKind::Break => false,
StmtKind::Continue => false,
}
}
pub fn any_over_body<F>(body: &[Stmt], func: &F) -> bool
where
F: Fn(&Expr) -> bool,
{
body.iter().any(|stmt| any_over_stmt(stmt, func))
}
static DUNDER_REGEX: Lazy<Regex> = Lazy::new(|| Regex::new(r"__[^\s]+__").unwrap());
/// Return `true` if the [`Stmt`] is an assignment to a dunder (like `__all__`).
@@ -379,6 +562,23 @@ pub fn is_super_call_with_arguments(func: &Expr, args: &[Expr]) -> bool {
}
}
/// Return `true` if the body uses `locals()`, `globals()`, `vars()`, `eval()`.
pub fn uses_magic_variable_access(checker: &Checker, body: &[Stmt]) -> bool {
any_over_body(body, &|expr| {
if let ExprKind::Call { func, .. } = &expr.node {
checker.resolve_call_path(func).map_or(false, |call_path| {
call_path.as_slice() == ["", "locals"]
|| call_path.as_slice() == ["", "globals"]
|| call_path.as_slice() == ["", "vars"]
|| call_path.as_slice() == ["", "eval"]
|| call_path.as_slice() == ["", "exec"]
})
} else {
false
}
})
}
/// Format the module name for a relative import.
pub fn format_import_from(level: Option<&usize>, module: Option<&str>) -> String {
let mut module_name = String::with_capacity(16);

View File

@@ -33,6 +33,10 @@ impl Range {
pub fn from_located<T>(located: &Located<T>) -> Self {
Range::new(located.location, located.end_location.unwrap())
}
pub fn contains(&self, other: &Range) -> bool {
self.location <= other.location && self.end_location >= other.end_location
}
}
#[derive(Debug)]
@@ -130,8 +134,22 @@ pub struct Binding<'a> {
/// The statement in which the [`Binding`] was defined.
pub source: Option<RefEquality<'a, Stmt>>,
/// Tuple of (scope index, range) indicating the scope and range at which
/// the binding was last used.
pub used: Option<(usize, Range)>,
/// the binding was last used in a runtime context.
pub runtime_usage: Option<(usize, Range)>,
/// Tuple of (scope index, range) indicating the scope and range at which
/// the binding was last used in a typing-time context.
pub typing_usage: Option<(usize, Range)>,
/// Tuple of (scope index, range) indicating the scope and range at which
/// the binding was last used in a synthetic context. This is used for
/// (e.g.) `__future__` imports, explicit re-exports, and other bindings
/// that should be considered used even if they're never referenced.
pub synthetic_usage: Option<(usize, Range)>,
}
#[derive(Copy, Clone)]
pub enum UsageContext {
Runtime,
Typing,
}
// Pyflakes defines the following binding hierarchy (via inheritance):
@@ -152,6 +170,19 @@ pub struct Binding<'a> {
// FutureImportation
impl<'a> Binding<'a> {
pub fn mark_used(&mut self, scope: usize, range: Range, context: UsageContext) {
match context {
UsageContext::Runtime => self.runtime_usage = Some((scope, range)),
UsageContext::Typing => self.typing_usage = Some((scope, range)),
}
}
pub fn used(&self) -> bool {
self.runtime_usage.is_some()
|| self.synthetic_usage.is_some()
|| self.typing_usage.is_some()
}
pub fn is_definition(&self) -> bool {
matches!(
self.kind,

View File

@@ -20,7 +20,7 @@ use crate::ast::operations::extract_all_names;
use crate::ast::relocate::relocate_expr;
use crate::ast::types::{
Binding, BindingKind, CallPath, ClassDef, FunctionDef, Lambda, Node, Range, RefEquality, Scope,
ScopeKind,
ScopeKind, UsageContext,
};
use crate::ast::visitor::{walk_excepthandler, Visitor};
use crate::ast::{branch_detection, cast, helpers, operations, visitor};
@@ -54,6 +54,7 @@ type DeferralContext<'a> = (Vec<usize>, Vec<RefEquality<'a, Stmt>>);
pub struct Checker<'a> {
// Input data.
path: &'a Path,
package: Option<&'a Path>,
autofix: flags::Autofix,
noqa: flags::Noqa,
pub(crate) settings: &'a Settings,
@@ -92,12 +93,14 @@ pub struct Checker<'a> {
in_deferred_type_definition: bool,
in_literal: bool,
in_subscript: bool,
in_type_checking_block: bool,
seen_import_boundary: bool,
futures_allowed: bool,
annotations_future_enabled: bool,
except_handlers: Vec<Vec<Vec<&'a str>>>,
// Check-specific state.
pub(crate) flake8_bugbear_seen: Vec<&'a Expr>,
pub(crate) type_checking_blocks: Vec<&'a Stmt>,
}
impl<'a> Checker<'a> {
@@ -108,6 +111,7 @@ impl<'a> Checker<'a> {
autofix: flags::Autofix,
noqa: flags::Noqa,
path: &'a Path,
package: Option<&'a Path>,
locator: &'a Locator,
style: &'a Stylist,
indexer: &'a Indexer,
@@ -118,6 +122,7 @@ impl<'a> Checker<'a> {
autofix,
noqa,
path,
package,
locator,
stylist: style,
indexer,
@@ -149,12 +154,14 @@ impl<'a> Checker<'a> {
in_deferred_type_definition: false,
in_literal: false,
in_subscript: false,
in_type_checking_block: false,
seen_import_boundary: false,
futures_allowed: true,
annotations_future_enabled: path.extension().map_or(false, |ext| ext == "pyi"),
except_handlers: vec![],
// Check-specific state.
flake8_bugbear_seen: vec![],
type_checking_blocks: vec![],
}
}
@@ -329,7 +336,9 @@ where
let index = self.bindings.len();
self.bindings.push(Binding {
kind: BindingKind::Global,
used: usage,
runtime_usage: None,
synthetic_usage: usage,
typing_usage: None,
range: *range,
source: Some(RefEquality(stmt)),
});
@@ -355,7 +364,9 @@ where
let index = self.bindings.len();
self.bindings.push(Binding {
kind: BindingKind::Nonlocal,
used: usage,
runtime_usage: None,
synthetic_usage: usage,
typing_usage: None,
range: *range,
source: Some(RefEquality(stmt)),
});
@@ -369,7 +380,7 @@ where
for index in self.scope_stack.iter().skip(1).rev().skip(1) {
if let Some(index) = self.scopes[*index].values.get(&name.as_str()) {
exists = true;
self.bindings[*index].used = usage;
self.bindings[*index].runtime_usage = usage;
}
}
@@ -667,7 +678,9 @@ where
name,
Binding {
kind: BindingKind::FunctionDefinition,
used: None,
runtime_usage: None,
synthetic_usage: None,
typing_usage: None,
range: Range::from_located(stmt),
source: Some(self.current_stmt().clone()),
},
@@ -819,7 +832,9 @@ where
name,
Binding {
kind: BindingKind::SubmoduleImportation(name, full_name),
used: None,
runtime_usage: None,
synthetic_usage: None,
typing_usage: None,
range: Range::from_located(alias),
source: Some(self.current_stmt().clone()),
},
@@ -838,9 +853,10 @@ where
name,
Binding {
kind: BindingKind::Importation(name, full_name),
runtime_usage: None,
// Treat explicit re-export as usage (e.g., `import applications
// as applications`).
used: if alias
synthetic_usage: if alias
.node
.asname
.as_ref()
@@ -857,6 +873,7 @@ where
} else {
None
},
typing_usage: None,
range: Range::from_located(alias),
source: Some(self.current_stmt().clone()),
},
@@ -1027,7 +1044,9 @@ where
}
}
if self.settings.rules.enabled(&Rule::UnnecessaryFutureImport) {
if self.settings.rules.enabled(&Rule::UnnecessaryFutureImport)
&& self.settings.target_version >= PythonVersion::Py37
{
if let Some("__future__") = module.as_deref() {
pyupgrade::rules::unnecessary_future_import(self, stmt, names);
}
@@ -1086,8 +1105,9 @@ where
name,
Binding {
kind: BindingKind::FutureImportation,
runtime_usage: None,
// Always mark `__future__` imports as used.
used: Some((
synthetic_usage: Some((
self.scopes[*(self
.scope_stack
.last()
@@ -1095,6 +1115,7 @@ where
.id,
Range::from_located(alias),
)),
typing_usage: None,
range: Range::from_located(alias),
source: Some(self.current_stmt().clone()),
},
@@ -1128,7 +1149,9 @@ where
"*",
Binding {
kind: BindingKind::StarImportation(*level, module.clone()),
used: None,
runtime_usage: None,
synthetic_usage: None,
typing_usage: None,
range: Range::from_located(stmt),
source: Some(self.current_stmt().clone()),
},
@@ -1182,9 +1205,10 @@ where
name,
Binding {
kind: BindingKind::FromImportation(name, full_name),
runtime_usage: None,
// Treat explicit re-export as usage (e.g., `from .applications
// import FastAPI as FastAPI`).
used: if alias
synthetic_usage: if alias
.node
.asname
.as_ref()
@@ -1201,6 +1225,7 @@ where
} else {
None
},
typing_usage: None,
range,
source: Some(self.current_stmt().clone()),
},
@@ -1377,9 +1402,6 @@ where
if self.settings.rules.enabled(&Rule::IfTuple) {
pyflakes::rules::if_tuple(self, stmt, test);
}
if self.settings.rules.enabled(&Rule::EmptyTypeCheckingBlock) {
flake8_type_checking::rules::empty_type_checking_block(self, test, body);
}
if self.settings.rules.enabled(&Rule::NestedIfStatements) {
flake8_simplify::rules::nested_if_statements(
self,
@@ -1709,7 +1731,9 @@ where
let index = self.bindings.len();
self.bindings.push(Binding {
kind: BindingKind::Assignment,
used: None,
runtime_usage: None,
synthetic_usage: None,
typing_usage: None,
range: Range::from_located(stmt),
source: Some(RefEquality(stmt)),
});
@@ -1770,7 +1794,9 @@ where
let index = self.bindings.len();
self.bindings.push(Binding {
kind: BindingKind::Assignment,
used: None,
runtime_usage: None,
synthetic_usage: None,
typing_usage: None,
range: Range::from_located(stmt),
source: Some(RefEquality(stmt)),
});
@@ -1829,6 +1855,25 @@ where
}
self.visit_expr(target);
}
StmtKind::If { test, body, orelse } => {
self.visit_expr(test);
if flake8_type_checking::helpers::is_type_checking_block(self, test) {
if self.settings.rules.enabled(&Rule::EmptyTypeCheckingBlock) {
flake8_type_checking::rules::empty_type_checking_block(self, test, body);
}
self.type_checking_blocks.push(stmt);
let prev_in_type_checking_block = self.in_type_checking_block;
self.in_type_checking_block = true;
self.visit_body(body);
self.in_type_checking_block = prev_in_type_checking_block;
} else {
self.visit_body(body);
}
self.visit_body(orelse);
}
_ => visitor::walk_stmt(self, stmt),
};
self.visible_scope = prev_visible_scope;
@@ -1844,7 +1889,9 @@ where
name,
Binding {
kind: BindingKind::ClassDefinition,
used: None,
runtime_usage: None,
synthetic_usage: None,
typing_usage: None,
range: Range::from_located(stmt),
source: Some(self.current_stmt().clone()),
},
@@ -3414,7 +3461,7 @@ where
[*(self.scope_stack.last().expect("No current scope found"))];
&scope.values.remove(&name.as_str())
} {
if self.bindings[*index].used.is_none() {
if !self.bindings[*index].used() {
if self.settings.rules.enabled(&Rule::UnusedVariable) {
let mut diagnostic = Diagnostic::new(
violations::UnusedVariable(name.to_string()),
@@ -3532,7 +3579,9 @@ where
&arg.node.arg,
Binding {
kind: BindingKind::Argument,
used: None,
runtime_usage: None,
synthetic_usage: None,
typing_usage: None,
range: Range::from_located(arg),
source: Some(self.current_stmt().clone()),
},
@@ -3631,7 +3680,9 @@ impl<'a> Checker<'a> {
self.bindings.push(Binding {
kind: BindingKind::Builtin,
range: Range::default(),
used: None,
runtime_usage: None,
synthetic_usage: None,
typing_usage: None,
source: None,
});
scope.values.insert(builtin, index);
@@ -3716,7 +3767,7 @@ impl<'a> Checker<'a> {
));
}
} else if in_current_scope {
if existing.used.is_none()
if !existing.used()
&& binding.redefines(existing)
&& (!self.settings.dummy_variable_rgx.is_match(name) || existing_is_import)
&& !(matches!(existing.kind, BindingKind::FunctionDefinition)
@@ -3749,7 +3800,9 @@ impl<'a> Checker<'a> {
let binding = match scope.values.get(&name) {
None => binding,
Some(index) => Binding {
used: self.bindings[*index].used,
runtime_usage: self.bindings[*index].runtime_usage,
synthetic_usage: self.bindings[*index].synthetic_usage,
typing_usage: self.bindings[*index].typing_usage,
..binding
},
};
@@ -3784,8 +3837,18 @@ impl<'a> Checker<'a> {
}
if let Some(index) = scope.values.get(&id.as_str()) {
let context = if self.in_type_checking_block
|| self.in_annotation
|| self.in_deferred_string_type_definition
|| self.in_deferred_type_definition
{
UsageContext::Typing
} else {
UsageContext::Runtime
};
// Mark the binding as used.
self.bindings[*index].used = Some((scope_id, Range::from_located(expr)));
self.bindings[*index].mark_used(scope_id, Range::from_located(expr), context);
if matches!(self.bindings[*index].kind, BindingKind::Annotation)
&& !self.in_deferred_string_type_definition
@@ -3813,8 +3876,11 @@ impl<'a> Checker<'a> {
if has_alias {
// Mark the sub-importation as used.
if let Some(index) = scope.values.get(full_name) {
self.bindings[*index].used =
Some((scope_id, Range::from_located(expr)));
self.bindings[*index].mark_used(
scope_id,
Range::from_located(expr),
context,
);
}
}
}
@@ -3827,8 +3893,11 @@ impl<'a> Checker<'a> {
if has_alias {
// Mark the sub-importation as used.
if let Some(index) = scope.values.get(full_name.as_str()) {
self.bindings[*index].used =
Some((scope_id, Range::from_located(expr)));
self.bindings[*index].mark_used(
scope_id,
Range::from_located(expr),
context,
);
}
}
}
@@ -3956,7 +4025,9 @@ impl<'a> Checker<'a> {
id,
Binding {
kind: BindingKind::Annotation,
used: None,
runtime_usage: None,
synthetic_usage: None,
typing_usage: None,
range: Range::from_located(expr),
source: Some(self.current_stmt().clone()),
},
@@ -3973,7 +4044,9 @@ impl<'a> Checker<'a> {
id,
Binding {
kind: BindingKind::LoopVar,
used: None,
runtime_usage: None,
synthetic_usage: None,
typing_usage: None,
range: Range::from_located(expr),
source: Some(self.current_stmt().clone()),
},
@@ -3986,7 +4059,9 @@ impl<'a> Checker<'a> {
id,
Binding {
kind: BindingKind::Binding,
used: None,
runtime_usage: None,
synthetic_usage: None,
typing_usage: None,
range: Range::from_located(expr),
source: Some(self.current_stmt().clone()),
},
@@ -4036,7 +4111,9 @@ impl<'a> Checker<'a> {
current,
&self.bindings,
)),
used: None,
runtime_usage: None,
synthetic_usage: None,
typing_usage: None,
range: Range::from_located(expr),
source: Some(self.current_stmt().clone()),
},
@@ -4049,7 +4126,9 @@ impl<'a> Checker<'a> {
id,
Binding {
kind: BindingKind::Assignment,
used: None,
runtime_usage: None,
synthetic_usage: None,
typing_usage: None,
range: Range::from_located(expr),
source: Some(self.current_stmt().clone()),
},
@@ -4229,14 +4308,30 @@ impl<'a> Checker<'a> {
}
fn check_dead_scopes(&mut self) {
if !self.settings.rules.enabled(&Rule::UnusedImport)
&& !self.settings.rules.enabled(&Rule::ImportStarUsage)
&& !self.settings.rules.enabled(&Rule::RedefinedWhileUnused)
&& !self.settings.rules.enabled(&Rule::UndefinedExport)
&& !self
if !(self.settings.rules.enabled(&Rule::UnusedImport)
|| self.settings.rules.enabled(&Rule::ImportStarUsage)
|| self.settings.rules.enabled(&Rule::RedefinedWhileUnused)
|| self.settings.rules.enabled(&Rule::UndefinedExport)
|| self
.settings
.rules
.enabled(&Rule::GlobalVariableNotAssigned)
|| self
.settings
.rules
.enabled(&Rule::RuntimeImportInTypeCheckingBlock)
|| self
.settings
.rules
.enabled(&Rule::TypingOnlyFirstPartyImport)
|| self
.settings
.rules
.enabled(&Rule::TypingOnlyThirdPartyImport)
|| self
.settings
.rules
.enabled(&Rule::TypingOnlyStandardLibraryImport))
{
return;
}
@@ -4313,7 +4408,7 @@ impl<'a> Checker<'a> {
| BindingKind::FutureImportation
) {
// Skip used exports from `__all__`
if binding.used.is_some()
if binding.used()
|| all_names
.as_ref()
.map(|names| names.contains(name))
@@ -4369,6 +4464,53 @@ impl<'a> Checker<'a> {
}
}
if self
.settings
.rules
.enabled(&Rule::RuntimeImportInTypeCheckingBlock)
|| self
.settings
.rules
.enabled(&Rule::TypingOnlyFirstPartyImport)
|| self
.settings
.rules
.enabled(&Rule::TypingOnlyThirdPartyImport)
|| self
.settings
.rules
.enabled(&Rule::TypingOnlyStandardLibraryImport)
{
for (.., index) in scope
.values
.iter()
.chain(scope.overridden.iter().map(|(a, b)| (a, b)))
{
let binding = &self.bindings[*index];
if let Some(diagnostic) =
flake8_type_checking::rules::runtime_import_in_type_checking_block(
binding,
&self.type_checking_blocks,
)
{
diagnostics.push(diagnostic);
}
if let Some(diagnostic) =
flake8_type_checking::rules::typing_only_runtime_import(
binding,
&self.type_checking_blocks,
self.package,
self.settings,
)
{
if self.settings.rules.enabled(diagnostic.kind.rule()) {
diagnostics.push(diagnostic);
}
}
}
}
if self.settings.rules.enabled(&Rule::UnusedImport) {
// Collect all unused imports by location. (Multiple unused imports at the same
// location indicates an `import from`.)
@@ -4395,7 +4537,7 @@ impl<'a> Checker<'a> {
};
// Skip used exports from `__all__`
if binding.used.is_some()
if binding.used()
|| all_names
.as_ref()
.map(|names| names.contains(name))
@@ -4861,6 +5003,7 @@ pub fn check_ast(
autofix: flags::Autofix,
noqa: flags::Noqa,
path: &Path,
package: Option<&Path>,
) -> Vec<Diagnostic> {
let mut checker = Checker::new(
settings,
@@ -4868,6 +5011,7 @@ pub fn check_ast(
autofix,
noqa,
path,
package,
locator,
stylist,
indexer,

View File

@@ -40,7 +40,7 @@ pub fn check_imports(
for block in &blocks {
if !block.imports.is_empty() {
if let Some(diagnostic) = isort::rules::organize_imports(
block, locator, indexer, settings, stylist, autofix, package,
block, locator, stylist, indexer, settings, autofix, package,
) {
diagnostics.push(diagnostic);
}
@@ -49,7 +49,7 @@ pub fn check_imports(
}
if settings.rules.enabled(&Rule::MissingRequiredImport) {
diagnostics.extend(isort::rules::add_required_imports(
&blocks, python_ast, locator, settings, autofix,
&blocks, python_ast, locator, stylist, settings, autofix,
));
}
diagnostics

View File

@@ -13,9 +13,11 @@ use crate::rules::pycodestyle::rules::{
use crate::rules::pygrep_hooks::rules::{blanket_noqa, blanket_type_ignore};
use crate::rules::pyupgrade::rules::unnecessary_coding_comment;
use crate::settings::{flags, Settings};
use crate::source_code::Stylist;
pub fn check_lines(
path: &Path,
stylist: &Stylist,
contents: &str,
commented_lines: &[usize],
doc_lines: &[usize],
@@ -139,6 +141,7 @@ pub fn check_lines(
if enforce_no_newline_at_end_of_file {
if let Some(diagnostic) = no_newline_at_end_of_file(
stylist,
contents,
matches!(autofix, flags::Autofix::Enabled)
&& settings.rules.should_fix(&Rule::NoNewLineAtEndOfFile),
@@ -164,13 +167,18 @@ mod tests {
use super::check_lines;
use crate::registry::Rule;
use crate::settings::{flags, Settings};
use crate::source_code::{Locator, Stylist};
#[test]
fn e501_non_ascii_char() {
let line = "'\u{4e9c}' * 2"; // 7 in UTF-32, 9 in UTF-8.
let locator = Locator::new(line);
let stylist = Stylist::from_contents(line, &locator);
let check_with_max_line_length = |line_length: usize| {
check_lines(
Path::new("foo.py"),
&stylist,
line,
&[],
&[],

View File

@@ -160,7 +160,7 @@ impl Plugin {
Plugin::Flake8Return => RuleCodePrefix::RET.into(),
Plugin::Flake8Simplify => RuleCodePrefix::SIM.into(),
Plugin::Flake8TidyImports => RuleCodePrefix::TID.into(),
Plugin::Flake8TypeChecking => RuleCodePrefix::TYP.into(),
Plugin::Flake8TypeChecking => RuleCodePrefix::TCH.into(),
Plugin::Flake8UnusedArguments => RuleCodePrefix::ARG.into(),
Plugin::Flake8UsePathlib => RuleCodePrefix::PTH.into(),
Plugin::McCabe => RuleCodePrefix::C9.into(),

View File

@@ -1,4 +1,3 @@
use std::borrow::Cow;
use std::fs::File;
use std::io::{BufReader, Read};
use std::path::{Path, PathBuf};
@@ -62,11 +61,11 @@ pub fn normalize_path_to<P: AsRef<Path>, R: AsRef<Path>>(path: P, project_root:
}
/// Convert an absolute path to be relative to the current working directory.
pub fn relativize_path(path: &Path) -> Cow<str> {
pub fn relativize_path(path: &Path) -> String {
if let Ok(path) = path.strip_prefix(&*path_dedot::CWD) {
return path.to_string_lossy();
return format!("{}", path.display());
}
path.to_string_lossy()
format!("{}", path.display())
}
/// Read a file's contents from disk.

View File

@@ -4,6 +4,8 @@
//! and subject to change drastically.
//!
//! [Ruff]: https://github.com/charliermarsh/ruff
#![forbid(unsafe_code)]
#![warn(clippy::pedantic)]
#![allow(
clippy::collapsible_else_if,
clippy::collapsible_if,
@@ -16,8 +18,8 @@
clippy::similar_names,
clippy::too_many_lines
)]
#![forbid(unsafe_code)]
mod assert_yaml_snapshot;
mod ast;
mod autofix;
pub mod cache;

View File

@@ -98,6 +98,7 @@ pub fn check_path(
autofix,
noqa,
path,
package,
));
}
if use_imports {
@@ -142,6 +143,7 @@ pub fn check_path(
{
diagnostics.extend(check_lines(
path,
stylist,
contents,
indexer.commented_lines(),
&doc_lines,

View File

@@ -429,7 +429,11 @@ ruff_macros::define_rule_mapping!(
EXE004 => rules::flake8_executable::rules::ShebangWhitespace,
EXE005 => rules::flake8_executable::rules::ShebangNewline,
// flake8-type-checking
TYP005 => rules::flake8_type_checking::rules::EmptyTypeCheckingBlock,
TCH001 => rules::flake8_type_checking::rules::TypingOnlyFirstPartyImport,
TCH002 => rules::flake8_type_checking::rules::TypingOnlyThirdPartyImport,
TCH003 => rules::flake8_type_checking::rules::TypingOnlyStandardLibraryImport,
TCH004 => rules::flake8_type_checking::rules::RuntimeImportInTypeCheckingBlock,
TCH005 => rules::flake8_type_checking::rules::EmptyTypeCheckingBlock,
// tryceratops
TRY004 => rules::tryceratops::rules::PreferTypeError,
TRY200 => rules::tryceratops::rules::ReraiseNoCause,
@@ -580,7 +584,7 @@ pub enum Linter {
#[prefix = "EXE"]
Flake8Executable,
/// [flake8-type-checking](https://pypi.org/project/flake8-type-checking/)
#[prefix = "TYP"]
#[prefix = "TCH"]
Flake8TypeChecking,
/// [tryceratops](https://pypi.org/project/tryceratops/1.1.0/)
#[prefix = "TRY"]

View File

@@ -240,13 +240,16 @@ pub fn python_files_in_path(
// Search for `pyproject.toml` files in all parent directories.
let mut resolver = Resolver::default();
let mut seen = FxHashSet::default();
if matches!(pyproject_strategy, PyprojectDiscovery::Hierarchical(..)) {
for path in &paths {
for ancestor in path.ancestors() {
if let Some(pyproject) = settings_toml(ancestor)? {
let (root, settings) =
resolve_scoped_settings(&pyproject, &Relativity::Parent, processor)?;
resolver.add(root, settings);
if seen.insert(ancestor) {
if let Some(pyproject) = settings_toml(ancestor)? {
let (root, settings) =
resolve_scoped_settings(&pyproject, &Relativity::Parent, processor)?;
resolver.add(root, settings);
}
}
}
}

View File

@@ -81,5 +81,8 @@ static REDIRECTS: Lazy<HashMap<&'static str, &'static str>> = Lazy::new(|| {
("PDV9", "PD9"),
("PDV90", "PD90"),
("PDV901", "PD901"),
// TODO(charlie): Remove by 2023-04-01.
("TYP", "TCH"),
("TYP001", "TCH001"),
])
});

View File

@@ -11,7 +11,7 @@ mod tests {
use crate::linter::test_path;
use crate::registry::Rule;
use crate::settings;
use crate::{assert_yaml_snapshot, settings};
#[test_case(Rule::CommentedOutCode, Path::new("ERA001.py"); "ERA001")]
fn rules(rule_code: Rule, path: &Path) -> Result<()> {
@@ -22,7 +22,7 @@ mod tests {
.as_path(),
&settings::Settings::for_rule(rule_code),
)?;
insta::assert_yaml_snapshot!(snapshot, diagnostics);
assert_yaml_snapshot!(snapshot, diagnostics);
Ok(())
}
}

View File

@@ -11,7 +11,8 @@ expression: diagnostics
row: 1
column: 10
fix:
content: ""
content:
- ""
location:
row: 1
column: 0
@@ -28,7 +29,8 @@ expression: diagnostics
row: 2
column: 22
fix:
content: ""
content:
- ""
location:
row: 2
column: 0
@@ -45,7 +47,8 @@ expression: diagnostics
row: 3
column: 6
fix:
content: ""
content:
- ""
location:
row: 3
column: 0
@@ -62,7 +65,8 @@ expression: diagnostics
row: 5
column: 13
fix:
content: ""
content:
- ""
location:
row: 5
column: 0
@@ -79,7 +83,8 @@ expression: diagnostics
row: 12
column: 16
fix:
content: ""
content:
- ""
location:
row: 12
column: 0

View File

@@ -10,7 +10,7 @@ mod tests {
use crate::linter::test_path;
use crate::registry::Rule;
use crate::settings;
use crate::{assert_yaml_snapshot, settings};
#[test_case(Rule::SysVersionSlice3Referenced, Path::new("YTT101.py"); "YTT101")]
#[test_case(Rule::SysVersion2Referenced, Path::new("YTT102.py"); "YTT102")]
@@ -30,7 +30,7 @@ mod tests {
.as_path(),
&settings::Settings::for_rule(rule_code),
)?;
insta::assert_yaml_snapshot!(snapshot, diagnostics);
assert_yaml_snapshot!(snapshot, diagnostics);
Ok(())
}
}

View File

@@ -10,6 +10,7 @@ mod tests {
use anyhow::Result;
use crate::assert_yaml_snapshot;
use crate::linter::test_path;
use crate::registry::Rule;
use crate::settings::Settings;
@@ -34,7 +35,7 @@ mod tests {
])
},
)?;
insta::assert_yaml_snapshot!(diagnostics);
assert_yaml_snapshot!(diagnostics);
Ok(())
}
@@ -58,7 +59,7 @@ mod tests {
])
},
)?;
insta::assert_yaml_snapshot!(diagnostics);
assert_yaml_snapshot!(diagnostics);
Ok(())
}
@@ -82,7 +83,7 @@ mod tests {
])
},
)?;
insta::assert_yaml_snapshot!(diagnostics);
assert_yaml_snapshot!(diagnostics);
Ok(())
}
@@ -106,7 +107,7 @@ mod tests {
])
},
)?;
insta::assert_yaml_snapshot!(diagnostics);
assert_yaml_snapshot!(diagnostics);
Ok(())
}
@@ -124,7 +125,7 @@ mod tests {
..Settings::for_rules(vec![Rule::DynamicallyTypedExpression])
},
)?;
insta::assert_yaml_snapshot!(diagnostics);
assert_yaml_snapshot!(diagnostics);
Ok(())
}
@@ -142,7 +143,7 @@ mod tests {
])
},
)?;
insta::assert_yaml_snapshot!(diagnostics);
assert_yaml_snapshot!(diagnostics);
Ok(())
}
@@ -160,7 +161,7 @@ mod tests {
])
},
)?;
insta::assert_yaml_snapshot!(diagnostics);
assert_yaml_snapshot!(diagnostics);
Ok(())
}
}

View File

@@ -11,7 +11,8 @@ expression: diagnostics
row: 5
column: 16
fix:
content: " -> None"
content:
- " -> None"
location:
row: 5
column: 22
@@ -28,7 +29,8 @@ expression: diagnostics
row: 11
column: 16
fix:
content: " -> None"
content:
- " -> None"
location:
row: 11
column: 27

View File

@@ -10,6 +10,7 @@ mod tests {
use anyhow::Result;
use test_case::test_case;
use crate::assert_yaml_snapshot;
use crate::linter::test_path;
use crate::registry::Rule;
use crate::settings::Settings;
@@ -38,7 +39,7 @@ mod tests {
.as_path(),
&Settings::for_rule(rule_code),
)?;
insta::assert_yaml_snapshot!(snapshot, diagnostics);
assert_yaml_snapshot!(snapshot, diagnostics);
Ok(())
}
@@ -58,7 +59,7 @@ mod tests {
..Settings::for_rule(Rule::HardcodedTempFile)
},
)?;
insta::assert_yaml_snapshot!("S108_extend", diagnostics);
assert_yaml_snapshot!("S108_extend", diagnostics);
Ok(())
}
}

View File

@@ -10,7 +10,7 @@ mod tests {
use crate::linter::test_path;
use crate::registry::Rule;
use crate::settings;
use crate::{assert_yaml_snapshot, settings};
#[test_case(Rule::BlindExcept, Path::new("BLE.py"); "BLE001")]
fn rules(rule_code: Rule, path: &Path) -> Result<()> {
@@ -21,7 +21,7 @@ mod tests {
.as_path(),
&settings::Settings::for_rule(rule_code),
)?;
insta::assert_yaml_snapshot!(snapshot, diagnostics);
assert_yaml_snapshot!(snapshot, diagnostics);
Ok(())
}
}

View File

@@ -10,7 +10,7 @@ mod tests {
use crate::linter::test_path;
use crate::registry::Rule;
use crate::settings;
use crate::{assert_yaml_snapshot, settings};
#[test_case(Rule::BooleanPositionalArgInFunctionDefinition, Path::new("FBT.py"); "FBT001")]
#[test_case(Rule::BooleanDefaultValueInFunctionDefinition, Path::new("FBT.py"); "FBT002")]
@@ -23,7 +23,7 @@ mod tests {
.as_path(),
&settings::Settings::for_rule(rule_code),
)?;
insta::assert_yaml_snapshot!(snapshot, diagnostics);
assert_yaml_snapshot!(snapshot, diagnostics);
Ok(())
}
}

View File

@@ -9,6 +9,7 @@ mod tests {
use anyhow::Result;
use test_case::test_case;
use crate::assert_yaml_snapshot;
use crate::linter::test_path;
use crate::registry::Rule;
use crate::settings::Settings;
@@ -49,7 +50,7 @@ mod tests {
.as_path(),
&Settings::for_rule(rule_code),
)?;
insta::assert_yaml_snapshot!(snapshot, diagnostics);
assert_yaml_snapshot!(snapshot, diagnostics);
Ok(())
}
@@ -68,7 +69,7 @@ mod tests {
..Settings::for_rules(vec![Rule::FunctionCallArgumentDefault])
},
)?;
insta::assert_yaml_snapshot!(snapshot, diagnostics);
assert_yaml_snapshot!(snapshot, diagnostics);
Ok(())
}
}

View File

@@ -22,8 +22,8 @@ use rustc_hash::FxHashMap;
use rustpython_ast::{Expr, ExprKind, Stmt};
use crate::ast::types::Range;
use crate::ast::visitor;
use crate::ast::visitor::Visitor;
use crate::ast::{helpers, visitor};
use crate::checkers::ast::Checker;
use crate::fix::Fix;
use crate::registry::Diagnostic;
@@ -73,7 +73,7 @@ pub fn unused_loop_control_variable(checker: &mut Checker, target: &Expr, body:
for (name, expr) in control_names {
// Ignore names that are already underscore-prefixed.
if name.starts_with('_') {
if checker.settings.dummy_variable_rgx.is_match(name) {
continue;
}
@@ -82,11 +82,15 @@ pub fn unused_loop_control_variable(checker: &mut Checker, target: &Expr, body:
continue;
}
let safe = !helpers::uses_magic_variable_access(checker, body);
let mut diagnostic = Diagnostic::new(
violations::UnusedLoopControlVariable(name.to_string()),
violations::UnusedLoopControlVariable {
name: name.to_string(),
safe,
},
Range::from_located(expr),
);
if checker.patch(diagnostic.kind.rule()) {
if safe && checker.patch(diagnostic.kind.rule()) {
// Prefix the variable name with an underscore.
diagnostic.amend(Fix::replacement(
format!("_{name}"),

View File

@@ -3,7 +3,9 @@ source: src/rules/flake8_bugbear/mod.rs
expression: diagnostics
---
- kind:
UnusedLoopControlVariable: i
UnusedLoopControlVariable:
name: i
safe: true
location:
row: 6
column: 4
@@ -11,7 +13,8 @@ expression: diagnostics
row: 6
column: 5
fix:
content: _i
content:
- _i
location:
row: 6
column: 4
@@ -20,7 +23,9 @@ expression: diagnostics
column: 5
parent: ~
- kind:
UnusedLoopControlVariable: k
UnusedLoopControlVariable:
name: k
safe: true
location:
row: 18
column: 12
@@ -28,7 +33,8 @@ expression: diagnostics
row: 18
column: 13
fix:
content: _k
content:
- _k
location:
row: 18
column: 12
@@ -37,7 +43,9 @@ expression: diagnostics
column: 13
parent: ~
- kind:
UnusedLoopControlVariable: i
UnusedLoopControlVariable:
name: i
safe: true
location:
row: 30
column: 4
@@ -45,7 +53,8 @@ expression: diagnostics
row: 30
column: 5
fix:
content: _i
content:
- _i
location:
row: 30
column: 4
@@ -54,7 +63,9 @@ expression: diagnostics
column: 5
parent: ~
- kind:
UnusedLoopControlVariable: k
UnusedLoopControlVariable:
name: k
safe: true
location:
row: 30
column: 12
@@ -62,7 +73,8 @@ expression: diagnostics
row: 30
column: 13
fix:
content: _k
content:
- _k
location:
row: 30
column: 12
@@ -70,4 +82,52 @@ expression: diagnostics
row: 30
column: 13
parent: ~
- kind:
UnusedLoopControlVariable:
name: bar
safe: false
location:
row: 34
column: 9
end_location:
row: 34
column: 12
fix: ~
parent: ~
- kind:
UnusedLoopControlVariable:
name: bar
safe: false
location:
row: 38
column: 9
end_location:
row: 38
column: 12
fix: ~
parent: ~
- kind:
UnusedLoopControlVariable:
name: bar
safe: false
location:
row: 42
column: 9
end_location:
row: 42
column: 12
fix: ~
parent: ~
- kind:
UnusedLoopControlVariable:
name: bar
safe: false
location:
row: 46
column: 9
end_location:
row: 46
column: 12
fix: ~
parent: ~

View File

@@ -11,7 +11,8 @@ expression: diagnostics
row: 18
column: 19
fix:
content: foo.bar
content:
- foo.bar
location:
row: 18
column: 0
@@ -28,7 +29,8 @@ expression: diagnostics
row: 19
column: 23
fix:
content: foo._123abc
content:
- foo._123abc
location:
row: 19
column: 0
@@ -45,7 +47,8 @@ expression: diagnostics
row: 20
column: 22
fix:
content: foo.abc123
content:
- foo.abc123
location:
row: 20
column: 0
@@ -62,7 +65,8 @@ expression: diagnostics
row: 21
column: 23
fix:
content: foo.abc123
content:
- foo.abc123
location:
row: 21
column: 0
@@ -79,7 +83,8 @@ expression: diagnostics
row: 22
column: 31
fix:
content: x.bar
content:
- x.bar
location:
row: 22
column: 14
@@ -96,7 +101,8 @@ expression: diagnostics
row: 23
column: 20
fix:
content: x.bar
content:
- x.bar
location:
row: 23
column: 3

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