Compare commits

...

105 Commits

Author SHA1 Message Date
Charlie Marsh
057414ddd4 Bump version to 0.0.199 2022-12-28 20:58:43 -05:00
Charlie Marsh
ca94e9aa26 Warn the user when max iteration count is reached (#1433) 2022-12-28 20:56:43 -05:00
Charlie Marsh
797b5bd261 Split into lint and lint-and-fix methods (#1432) 2022-12-28 20:14:33 -05:00
Charlie Marsh
a64f62f439 Revert setup.py change 2022-12-28 19:34:20 -05:00
Charlie Marsh
058ee8e6bf Add a --diff flag to dry-run autofixes (#1431) 2022-12-28 19:21:29 -05:00
Charlie Marsh
39fc1f0c1b Add a note on autofix settings 2022-12-28 17:26:38 -05:00
Colin Delahunty
34842b4c4b PyUpgrade: Replace pipes with capture_output=True (#1415) 2022-12-28 16:53:35 -05:00
Charlie Marsh
dfa6fa8f83 Check in updated snapshots 2022-12-28 16:42:55 -05:00
Colin Delahunty
6131c819ed Rewrite xml.etree.cElementTree to xml.etree.ElementTree (#1426) 2022-12-28 16:30:36 -05:00
Hannes Käufler
79ba420faa Extract duplicated logic into method (#1428) 2022-12-28 16:10:53 -05:00
Charlie Marsh
d16ba890ae Turn off wasm-pack tests (#1427) 2022-12-28 12:55:25 -05:00
Charlie Marsh
6b6851bf1f Update JSON schema 2022-12-28 12:27:01 -05:00
Charlie Marsh
056718ce75 Remove stray Plugins doc 2022-12-28 12:24:48 -05:00
Charlie Marsh
4521fdf021 Only test --lib for wasm-pack 2022-12-28 10:28:40 -05:00
Maksudul Haque
8e479628f2 Add Support for GitLab CI Code Quality Report Format (#1424) 2022-12-28 10:10:43 -05:00
Charlie Marsh
2a11c4b1f1 Try increasing wasm-bindgen timeout 2022-12-28 07:39:23 -05:00
Anders Kaseorg
a8cde5a936 Check for keyword arguments before the last star argument (#1420) 2022-12-27 23:20:03 -05:00
Charlie Marsh
1822b57ed5 Remove 'static 2022-12-27 21:57:32 -05:00
Charlie Marsh
c679570041 Bump version to 0.0.198 2022-12-27 21:39:53 -05:00
Charlie Marsh
edcb3a7217 Support --select ALL to enable all error codes (#1418) 2022-12-27 21:38:26 -05:00
Charlie Marsh
6e43dc7270 Add nbQA support to the docs (#1417) 2022-12-27 21:24:07 -05:00
Charlie Marsh
570d0864f2 Add rule to detect keyword arguments before starred arguments (#1416) 2022-12-27 21:17:22 -05:00
Charlie Marsh
d22e96916c Automatically detect and respect indentation and quotation code style (#1413) 2022-12-27 19:45:50 -05:00
Charlie Marsh
043d31dcdf Bump version to 0.0.197 2022-12-27 17:05:15 -05:00
Charlie Marsh
1392e4cced Default to double quotes in code_gen.rs (#1412) 2022-12-27 16:17:49 -05:00
Charlie Marsh
59ee89a091 Fix it_converts_docstring_conventions test 2022-12-27 15:41:29 -05:00
Charlie Marsh
6a7c3728ee Set convention in flake8-to-ruff (#1410) 2022-12-27 13:51:24 -05:00
Charlie Marsh
0a60eb0aca Fix invalid reference to ruff_options.rs (#1409) 2022-12-27 12:12:28 -05:00
Charlie Marsh
3e96803033 Bump version to 0.0.196 2022-12-27 12:02:02 -05:00
Colin Delahunty
c59035139c Pyupgrade: converts universal_newlines to text in subprocess.run (#1403) 2022-12-27 12:01:27 -05:00
Charlie Marsh
7632d7eda7 Allow specification of explicit docstring convention (#1408) 2022-12-27 11:50:28 -05:00
Charlie Marsh
b4dbe62da0 Add cargo +nightly dev generate-all (#1404) 2022-12-27 10:07:18 -05:00
Harutaka Kawamura
9106d5338b Replace make_tokenize with make_tokenizer_located (#1405) 2022-12-27 10:07:03 -05:00
Reiner Gerecke
534d8d049c Support isort's force-single-line option (#1366) 2022-12-27 08:51:32 -05:00
Charlie Marsh
e692c4a2cc Tweak secret detection for playground releases (#1402) 2022-12-27 08:41:53 -05:00
Reiner Gerecke
e0b39fa63e Implement pyupgrade check for io.open alias (#1399) 2022-12-27 07:47:40 -05:00
Charlie Marsh
320a48977b Tweak README again 2022-12-26 21:17:18 -05:00
Charlie Marsh
0d05aaeb6e Add monorepo note 2022-12-26 21:00:14 -05:00
Charlie Marsh
1e4b1533ad Bump version to 0.0.195 2022-12-26 20:41:39 -05:00
Charlie Marsh
df4f5358f9 Bump pyupgrade implementation count 2022-12-26 19:56:12 -05:00
Colin Delahunty
58c383401c Replace typing.Text with str (#1391) 2022-12-26 19:55:41 -05:00
Charlie Marsh
018b9a2977 Only run playground release in main repo (#1396) 2022-12-26 19:45:04 -05:00
Charlie Marsh
658cb87ddd Enable Quick Fix in the playground (#1395) 2022-12-26 19:25:50 -05:00
Charlie Marsh
0d35087bc6 Choose a more interesting example snippet (#1394) 2022-12-26 15:19:17 -05:00
Charlie Marsh
b721125af9 Add badge to playground (#1393) 2022-12-26 15:13:55 -05:00
Charlie Marsh
20d6b21d77 Add ESLint, Prettier, and TypeScript checks (#1384) 2022-12-26 15:08:22 -05:00
Charlie Marsh
1a27992f47 Enable preview deployments for playground (#1383) 2022-12-26 14:52:13 -05:00
Charlie Marsh
89cebe1ce2 Update name of Playground job 2022-12-26 12:10:22 -05:00
Reiner Gerecke
bdb1505262 Web playground with WASM (#1279) 2022-12-26 12:09:17 -05:00
Charlie Marsh
8c018e8261 Add settings validation to lib.rs 2022-12-26 10:12:07 -05:00
Colin Delahunty
debd909b2c Magic Trailing Commas in isort (#1363) 2022-12-26 09:40:02 -05:00
Reiner Gerecke
fa54538bd1 Only re-associate inline comments during normalization when necessary (#1380) 2022-12-26 07:52:13 -05:00
Reiner Gerecke
939f738a71 Update rust python to handle files with BOM (#1379) 2022-12-26 07:03:13 -05:00
Charlie Marsh
b0f30bef8f Add support for ruff.toml (#1378) 2022-12-25 21:55:07 -05:00
Charlie Marsh
28c45eb2a3 Remove required versions from pyproject.toml 2022-12-25 20:21:01 -05:00
Charlie Marsh
4dc45912e8 Run cargo dev commands 2022-12-25 20:12:12 -05:00
Charlie Marsh
5ef8bff341 Bump version to 0.0.194 2022-12-25 19:54:45 -05:00
Charlie Marsh
2ab8f77223 Update command-line help text 2022-12-25 19:54:14 -05:00
Charlie Marsh
8b72f55a09 Add --required-version (#1376) 2022-12-25 19:53:50 -05:00
Charlie Marsh
19121219fb Avoid double-extending past the end when showing source (#1377) 2022-12-25 19:52:42 -05:00
Charlie Marsh
d9355c989a Add a --fix-only command-line and pyproject.toml option (#1375) 2022-12-25 18:49:56 -05:00
Charlie Marsh
ec80d1cd85 Respect natural ordering for imports (#1374) 2022-12-25 18:11:41 -05:00
Charlie Marsh
9bb470c7d4 Ignore unused arguments for @overload stubs (#1373) 2022-12-25 17:22:31 -05:00
Harutaka Kawamura
dca3fcd8d1 Improve excepthandler_name_range (#1368) 2022-12-25 00:12:12 -05:00
Harutaka Kawamura
10f75c9620 Fix F841 (UnusedVariable) range in except handler (#1367) 2022-12-24 22:55:55 -05:00
Charlie Marsh
cc2110449c Run cargo dev commands 2022-12-24 15:06:12 -05:00
Charlie Marsh
f6ca49e05f Bump version to 0.0.193 2022-12-24 14:56:26 -05:00
Charlie Marsh
9a7331b2e2 Annotate RUF100 messages with unmatched, disabled, and unknown codes (#1365) 2022-12-24 14:55:55 -05:00
Edgar R. M
4888afd423 Generate JSON schema for Ruff options (#1329) 2022-12-24 14:10:22 -05:00
Sawbez
0dc523b081 Add autofix for W605 [InvalidEscapeSequence] (#1361) 2022-12-24 13:46:28 -05:00
Harutaka Kawamura
63772e335d Fix B025 location (#1360) 2022-12-24 12:22:11 -05:00
Reiner Gerecke
7f4ff1e38f Fix false-positive in RET504 when referencing globals (#1358) 2022-12-24 12:02:57 -05:00
Reiner Gerecke
32ebc1d227 Don't trigger E721 when comparing with None (#1356) 2022-12-24 04:45:40 -05:00
Sawbez
4ded155dc0 Add autofix for W292 [NoNewLineAtEndOfFile] (#1354) 2022-12-23 23:14:17 -05:00
Harutaka Kawamura
201e1250de Update RustPython to use the correct BinOp location (#1355) 2022-12-23 22:58:39 -05:00
Reiner Gerecke
102b049a32 Add cache-dir to command-line and pyproject.toml (#1351) 2022-12-23 22:58:29 -05:00
Charlie Marsh
74f49eda64 Bump compatibility to 3.11 (#1352) 2022-12-23 12:12:11 -05:00
Reiner Gerecke
9da3e2cca1 Implement "native literals" check from pyupgrade (#1350) 2022-12-23 11:40:32 -05:00
Charlie Marsh
e290050821 Avoid enabling all EM checks at once (#1349) 2022-12-23 08:25:07 -05:00
Charlie Marsh
bc9ed0a4ef Tweak LSP docs 2022-12-22 22:16:32 -05:00
Charlie Marsh
20b9b44973 Link to ruff-lsp docs 2022-12-22 21:53:11 -05:00
Charlie Marsh
6e5a553235 Update Neovim instructions 2022-12-22 21:52:30 -05:00
Charlie Marsh
2a08a63f17 Add a link to the PyCharm plugin (#1345) 2022-12-22 21:50:24 -05:00
Colin Delahunty
d4290e6721 Update CONTRIBUTING.md (#1344) 2022-12-22 21:04:19 -05:00
Charlie Marsh
51bda28a7d Bump version to 0.0.192 2022-12-22 17:31:31 -05:00
Reiner Gerecke
cc26051b7a Implement "datetime.UTC alias" check from pyupgrade (#1341) 2022-12-22 17:21:36 -05:00
Charlie Marsh
3ac5a9aa31 Respect --force-exclude for files passed via stdin (#1342) 2022-12-22 16:40:15 -05:00
Charlie Marsh
451047c30d Exclude directly-passed files nested in excluded subdirectories 2022-12-22 15:08:11 -05:00
Charlie Marsh
6907df489b Extend false-positive list for flake8-boolean-trap (#1338) 2022-12-22 10:56:04 -05:00
Charlie Marsh
970f882b03 Set force-exclude for pre-commit in README (#1337) 2022-12-22 10:51:20 -05:00
Charlie Marsh
3eff9a2860 Allow unittest methods in flake8-boolean-trap (#1333) 2022-12-22 08:40:22 -05:00
Charlie Marsh
a4a24a0ef3 Add some more repositories to the user list (#1328) 2022-12-21 22:16:47 -05:00
Charlie Marsh
48e3c046b0 Fix integration tests 2022-12-21 21:25:37 -05:00
Charlie Marsh
03e4f5be8a Bump version to 0.0.191 2022-12-21 21:16:21 -05:00
Charlie Marsh
99657b7d92 Implement E401 ("multiple imports on one line") (#1326) 2022-12-21 21:15:57 -05:00
Charlie Marsh
40377aa1fc Move number of errors to the bottom of the output summary (#1325) 2022-12-21 21:04:26 -05:00
Charlie Marsh
2a37017e8c Add src to Settings hash 2022-12-21 21:01:20 -05:00
Charlie Marsh
ff66d08cef Run generate-options 2022-12-21 20:58:14 -05:00
Charlie Marsh
dad8035eef Support shell expansion in src field (#1324) 2022-12-21 20:57:20 -05:00
Charlie Marsh
bf5fec342c Support shell expansion in extend paths (#1323) 2022-12-21 20:46:38 -05:00
Charlie Marsh
66a6c81ebf Infer package roots when running via stdin (#1321) 2022-12-21 20:30:10 -05:00
Charlie Marsh
5c70f5044b Improve debug logging in flake8-to-ruff (#1320) 2022-12-21 20:05:48 -05:00
Charlie Marsh
953d141ab2 Support code redirects in flake8-to-ruff (#1318) 2022-12-21 19:31:20 -05:00
Charlie Marsh
07dba46039 Extract line length from pyproject.toml Black section (#1317) 2022-12-21 19:05:18 -05:00
Ran Benita
3b02da9d7b Fix false positive DTZ001 on datetime(2000, 1, 1, 0, 0, 0, 0, utc) (#1308) 2022-12-21 19:03:36 -05:00
219 changed files with 15737 additions and 1878 deletions

View File

@@ -12,7 +12,7 @@ env:
RUSTUP_MAX_RETRIES: 10
jobs:
cargo_build:
cargo-build:
name: "cargo build"
runs-on: ubuntu-latest
steps:
@@ -36,14 +36,14 @@ jobs:
${{ runner.os }}-build-
${{ runner.os }}-
- run: cargo build --all --release
- run: ./target/release/ruff_dev generate-rules-table
- run: ./target/release/ruff_dev generate-options
- run: git diff --quiet README.md || echo "::error file=README.md::This file is outdated. You may have to rerun 'cargo dev generate-options' and/or 'cargo dev generate-rules-table'."
- run: ./target/release/ruff_dev generate-check-code-prefix
- run: git diff --quiet src/checks_gen.rs || echo "::error file=src/checks_gen.rs::This file is outdated. You may have to rerun 'cargo dev generate-check-code-prefix'."
- run: git diff --exit-code -- README.md src/checks_gen.rs
- run: ./target/release/ruff_dev generate-all
- run: git diff --quiet README.md || echo "::error file=README.md::This file is outdated. Run 'cargo +nightly dev generate-all'."
- run: git diff --quiet src/checks_gen.rs || echo "::error file=src/checks_gen.rs::This file is outdated. Run 'cargo +nightly dev generate-all'."
- run: git diff --quiet ruff.schema.json || echo "::error file=ruff.schema.json::This file is outdated. Run 'cargo +nightly dev generate-all'."
- run: git diff --quiet playground/src/ruff_options.ts || echo "::error file=playground/src/ruff_options.ts::This file is outdated. Run 'cargo +nightly dev generate-all'."
- run: git diff --exit-code -- README.md src/checks_gen.rs ruff.schema.json playground/src/ruff_options.ts
cargo_fmt:
cargo-fmt:
name: "cargo fmt"
runs-on: ubuntu-latest
steps:
@@ -79,6 +79,7 @@ jobs:
toolchain: nightly-2022-11-01
override: true
components: clippy
target: wasm32-unknown-unknown
- uses: actions/cache@v3
env:
cache-name: cache-cargo
@@ -92,8 +93,9 @@ jobs:
${{ runner.os }}-build-
${{ runner.os }}-
- run: cargo clippy --workspace --all-targets --all-features -- -D warnings -W clippy::pedantic
- run: cargo clippy --workspace --target wasm32-unknown-unknown --all-features -- -D warnings -W clippy::pedantic
cargo_test:
cargo-test:
name: "cargo test"
runs-on: ubuntu-latest
steps:
@@ -119,7 +121,37 @@ jobs:
- run: cargo test --all
- run: cargo test --package ruff --test black_compatibility_test -- --ignored
maturin_build:
# TODO(charlie): Re-enable the `wasm-pack` tests.
# See: https://github.com/charliermarsh/ruff/issues/1425
# wasm-pack-test:
# name: "wasm-pack test"
# runs-on: ubuntu-latest
# env:
# WASM_BINDGEN_TEST_TIMEOUT: 60
# steps:
# - uses: actions/checkout@v3
# - uses: actions-rs/toolchain@v1
# with:
# profile: minimal
# toolchain: nightly-2022-11-01
# override: true
# - uses: actions/cache@v3
# env:
# cache-name: cache-cargo
# with:
# path: |
# ~/.cargo/registry
# ~/.cargo/git
# key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/Cargo.lock') }}
# restore-keys: |
# ${{ runner.os }}-build-${{ env.cache-name }}-
# ${{ runner.os }}-build-
# ${{ runner.os }}-
# - uses: jetli/wasm-pack-action@v0.4.0
# - uses: jetli/wasm-bindgen-action@v0.2.0
# - run: wasm-pack test --node
maturin-build:
name: "maturin build"
runs-on: ubuntu-latest
steps:
@@ -131,7 +163,7 @@ jobs:
override: true
- uses: actions/setup-python@v4
with:
python-version: "3.10"
python-version: "3.11"
- run: pip install maturin
- uses: actions/cache@v3
env:

50
.github/workflows/playground.yaml vendored Normal file
View File

@@ -0,0 +1,50 @@
name: "[Playground] Release"
on:
workflow_dispatch:
push:
branches: [main]
env:
CARGO_INCREMENTAL: 0
CARGO_NET_RETRY: 10
RUSTUP_MAX_RETRIES: 10
jobs:
publish:
runs-on: ubuntu-latest
env:
CF_API_TOKEN_EXISTS: ${{ secrets.CF_API_TOKEN != '' }}
steps:
- uses: actions/checkout@v3
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: nightly-2022-11-01
override: true
target: wasm32-unknown-unknown
- uses: actions/setup-node@v3
with:
node-version: 18
cache: "npm"
cache-dependency-path: playground/package-lock.json
- uses: jetli/wasm-pack-action@v0.4.0
- uses: jetli/wasm-bindgen-action@v0.2.0
- name: "Run wasm-pack"
run: wasm-pack build --target web --out-dir playground/src/pkg
- name: "Install Node dependencies"
run: npm ci
working-directory: playground
- name: "Run TypeScript checks"
run: npm run check
working-directory: playground
- name: "Build JavaScript bundle"
run: npm run build
working-directory: playground
- name: "Deploy to Cloudflare Pages"
if: ${{ env.CF_API_TOKEN_EXISTS == 'true' }}
uses: cloudflare/wrangler-action@2.0.0
with:
apiToken: ${{ secrets.CF_API_TOKEN }}
accountId: ${{ secrets.CF_ACCOUNT_ID }}
command: pages publish playground/dist --project-name=ruff --branch ${GITHUB_HEAD_REF} --commit-hash ${GITHUB_SHA}

View File

@@ -1,6 +1,6 @@
repos:
- repo: https://github.com/charliermarsh/ruff-pre-commit
rev: v0.0.190
rev: v0.0.199
hooks:
- id: ruff

View File

@@ -48,8 +48,8 @@ prior to merging.
There are four phases to adding a new lint rule:
1. Define the rule in `src/checks.rs`.
2. Define the _logic_ for triggering the rule in `src/check_ast.rs` (for AST-based checks),
`src/check_tokens.rs` (for token-based checks), or `src/check_lines.rs` (for text-based checks).
2. Define the _logic_ for triggering the rule in `src/checkers/ast.rs` (for AST-based checks),
`src/checkers/tokens.rs` (for token-based checks), or `src/checkers/lines.rs` (for text-based checks).
3. Add a test fixture.
4. Update the generated files (documentation and generated code).
@@ -59,9 +59,9 @@ pattern implemented therein.
To trigger the rule, you'll likely want to augment the logic in `src/check_ast.rs`, which defines
the Python AST visitor, responsible for iterating over the abstract syntax tree and collecting
lint-rule violations as it goes. If you need to inspect the AST, you can run `cargo dev print-ast`
with a Python file. Grep for the `Check::new` invocations to understand how other, similar rules
are implemented.
lint-rule violations as it goes. If you need to inspect the AST, you can run
`cargo +nightly dev print-ast` with a Python file. Grep for the `Check::new` invocations to
understand how other, similar rules are implemented.
To add a test fixture, create a file under `resources/test/fixtures`, named to match the `CheckCode`
you defined earlier (e.g., `E402.py`). This file should contain a variety of violations and
@@ -79,9 +79,7 @@ Then, run `cargo test`. Your test will fail, but you'll be prompted to follow-up
`cargo insta review`. Accept the generated snapshot, then commit the snapshot file alongside the
rest of your changes.
Finally, to update the documentation, run `cargo dev generate-rules-table` from the repo root. To
update the generated prefix map, run `cargo dev generate-check-code-prefix`. Both of these commands
should be run whenever a new check is added to the codebase.
Finally, regenerate the documentation and generated code with `cargo +nightly dev generate-all`.
### Example: Adding a new configuration option
@@ -105,7 +103,7 @@ You may also want to add the new configuration option to the `flake8-to-ruff` to
responsible for converting `flake8` configuration files to Ruff's TOML format. This logic
lives in `flake8_to_ruff/src/converter.rs`.
To update the documentation for supported configuration options, run `cargo dev generate-options`.
Finally, regenerate the documentation and generated code with `cargo +nightly dev generate-all`.
## Release process

325
Cargo.lock generated
View File

@@ -61,9 +61,9 @@ dependencies = [
[[package]]
name = "anyhow"
version = "1.0.66"
version = "1.0.68"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "216261ddc8289130e551ddcd5ce8a064710c0d064a4d2895c67151c92b5443f6"
checksum = "2cb2f989d18dd141ab8ae82f64d1a8cdd37e0840f73a406896cf5e99502fab61"
[[package]]
name = "ascii"
@@ -86,7 +86,7 @@ version = "2.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa3d466004a8b4cb1bc34044240a2fd29d17607e2e3bd613eb44fd48e8100da3"
dependencies = [
"bstr 1.0.1",
"bstr 1.1.0",
"doc-comment",
"predicates",
"predicates-core",
@@ -160,9 +160,9 @@ dependencies = [
[[package]]
name = "bstr"
version = "1.0.1"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fca0852af221f458706eb0725c03e4ed6c46af9ac98e6a689d5e634215d594dd"
checksum = "b45ea9b00a7b3f2988e9a65ad3917e62123c38dba709b666506207be96d1790b"
dependencies = [
"memchr",
"once_cell",
@@ -193,9 +193,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5"
[[package]]
name = "cc"
version = "1.0.77"
version = "1.0.78"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e9f73505338f7d905b19d18738976aae232eb46b8efc15554ffc56deb5d9ebe4"
checksum = "a20104e2335ce8a659d6dd92a51a767a0c062599c73b343fd152cb401e828c3d"
[[package]]
name = "cfg-if"
@@ -280,9 +280,9 @@ dependencies = [
[[package]]
name = "clap"
version = "4.0.29"
version = "4.0.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4d63b9e9c07271b9957ad22c173bae2a4d9a81127680962039296abcd2f8251d"
checksum = "a7db700bc935f9e43e88d00b0850dae18a63773cfbec6d8e070fccf7fef89a39"
dependencies = [
"bitflags",
"clap_derive",
@@ -295,11 +295,11 @@ dependencies = [
[[package]]
name = "clap_complete"
version = "4.0.6"
version = "4.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b7b3c9eae0de7bf8e3f904a5e40612b21fb2e2e566456d177809a48b892d24da"
checksum = "10861370d2ba66b0f5989f83ebf35db6421713fd92351790e7fdd6c36774c56b"
dependencies = [
"clap 4.0.29",
"clap 4.0.32",
]
[[package]]
@@ -308,7 +308,7 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4160b4a4f72ef58bd766bad27c09e6ef1cc9d82a22f6a0f55d152985a4a48e31"
dependencies = [
"clap 4.0.29",
"clap 4.0.32",
"clap_complete",
"clap_complete_fig",
]
@@ -319,7 +319,7 @@ version = "4.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46b30e010e669cd021e5004f3be26cff6b7c08d2a8a0d65b48d43a8cc0efd6c3"
dependencies = [
"clap 4.0.29",
"clap 4.0.32",
"clap_complete",
]
@@ -422,6 +422,26 @@ dependencies = [
"winapi",
]
[[package]]
name = "console_error_panic_hook"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc"
dependencies = [
"cfg-if 1.0.0",
"wasm-bindgen",
]
[[package]]
name = "console_log"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "501a375961cef1a0d44767200e66e4a559283097e91d0730b1d75dfb2f8a1494"
dependencies = [
"log",
"web-sys",
]
[[package]]
name = "core-foundation-sys"
version = "0.8.3"
@@ -524,9 +544,9 @@ checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
[[package]]
name = "cxx"
version = "1.0.83"
version = "1.0.85"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bdf07d07d6531bfcdbe9b8b739b104610c6508dcc4d63b410585faf338241daf"
checksum = "5add3fc1717409d029b20c5b6903fc0c0b02fa6741d820054f4a2efa5e5816fd"
dependencies = [
"cc",
"cxxbridge-flags",
@@ -536,9 +556,9 @@ dependencies = [
[[package]]
name = "cxx-build"
version = "1.0.83"
version = "1.0.85"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2eb5b96ecdc99f72657332953d4d9c50135af1bac34277801cc3937906ebd39"
checksum = "b4c87959ba14bc6fbc61df77c3fcfe180fc32b93538c4f1031dd802ccb5f2ff0"
dependencies = [
"cc",
"codespan-reporting",
@@ -551,15 +571,15 @@ dependencies = [
[[package]]
name = "cxxbridge-flags"
version = "1.0.83"
version = "1.0.85"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac040a39517fd1674e0f32177648334b0f4074625b5588a64519804ba0553b12"
checksum = "69a3e162fde4e594ed2b07d0f83c6c67b745e7f28ce58c6df5e6b6bef99dfb59"
[[package]]
name = "cxxbridge-macro"
version = "1.0.83"
version = "1.0.85"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1362b0ddcfc4eb0a1f57b68bd77dd99f0e826958a96abd0ae9bd092e114ffed6"
checksum = "3e7e2adeb6a0d4a282e581096b06e1791532b7d576dcde5ccd9382acf55db8e6"
dependencies = [
"proc-macro2",
"quote",
@@ -644,6 +664,12 @@ version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10"
[[package]]
name = "dyn-clone"
version = "1.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c9b0705efd4599c15a38151f4721f7bc388306f61084d3bfd50bd07fbca5cb60"
[[package]]
name = "either"
version = "1.8.0"
@@ -706,9 +732,9 @@ dependencies = [
[[package]]
name = "filetime"
version = "0.2.18"
version = "0.2.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4b9663d381d07ae25dc88dbdf27df458faa83a9b25336bcac83d5e452b5fc9d3"
checksum = "4e884668cd0c7480504233e951174ddc3b382f7c2666e3b7310b5c4e7b0c37f9"
dependencies = [
"cfg-if 1.0.0",
"libc",
@@ -724,10 +750,10 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
[[package]]
name = "flake8-to-ruff"
version = "0.0.190-dev.0"
version = "0.0.199-dev.0"
dependencies = [
"anyhow",
"clap 4.0.29",
"clap 4.0.32",
"configparser",
"once_cell",
"regex",
@@ -735,6 +761,8 @@ dependencies = [
"rustc-hash",
"serde",
"serde_json",
"strum",
"strum_macros",
"toml",
]
@@ -944,9 +972,9 @@ dependencies = [
[[package]]
name = "insta"
version = "1.22.0"
version = "1.23.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "197f4e300af8b23664d4077bf5c40e0afa9ba66a567bb5a51d3def3c7b287d1c"
checksum = "e48b08a091dfe5b09a6a9688c468fdd5b4396e92ce09e2eb932f0884b02788a4"
dependencies = [
"console",
"lazy_static",
@@ -977,9 +1005,9 @@ dependencies = [
[[package]]
name = "is-terminal"
version = "0.4.1"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "927609f78c2913a6f6ac3c27a4fe87f43e2a35367c0c4b0f8265e8f49a104330"
checksum = "28dfb6c8100ccc63462345b67d1bbc3679177c75ee4bf59bf29c8b1d110b8189"
dependencies = [
"hermit-abi 0.2.6",
"io-lifetimes",
@@ -998,9 +1026,9 @@ dependencies = [
[[package]]
name = "itoa"
version = "1.0.4"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4217ad341ebadf8d8e724e264f13e593e0648f5b3e94b3896a5df283be015ecc"
checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440"
[[package]]
name = "joinery"
@@ -1107,9 +1135,9 @@ dependencies = [
[[package]]
name = "libc"
version = "0.2.138"
version = "0.2.139"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db6d7e329c562c5dfab7a46a2afabc8b987ab9a4834c9d1ca04dc54c1546cef8"
checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79"
[[package]]
name = "libcst"
@@ -1137,9 +1165,9 @@ dependencies = [
[[package]]
name = "link-cplusplus"
version = "1.0.7"
version = "1.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9272ab7b96c9046fbc5bc56c06c117cb639fe2d509df0c421cad82d2915cf369"
checksum = "ecd207c9c713c34f95a097a5b029ac2ce6010530c7b49d7fea24d977dede04f5"
dependencies = [
"cc",
]
@@ -1152,9 +1180,9 @@ checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f"
[[package]]
name = "linux-raw-sys"
version = "0.1.3"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f9f08d8963a6c613f4b1a78f4f4a4dbfadf8e6545b2d72861731e4858b8b47f"
checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4"
[[package]]
name = "lock_api"
@@ -1226,6 +1254,12 @@ dependencies = [
"windows-sys",
]
[[package]]
name = "natord"
version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "308d96db8debc727c3fd9744aac51751243420e46edf401010908da7f8d5e57c"
[[package]]
name = "new_debug_unreachable"
version = "1.0.4"
@@ -1326,11 +1360,11 @@ dependencies = [
[[package]]
name = "num_cpus"
version = "1.14.0"
version = "1.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f6058e64324c71e02bc2b150e4f3bc8286db6c83092132ffa3f6b1eab0f9def5"
checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b"
dependencies = [
"hermit-abi 0.1.19",
"hermit-abi 0.2.6",
"libc",
]
@@ -1377,9 +1411,9 @@ dependencies = [
[[package]]
name = "paste"
version = "1.0.9"
version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1de2e551fb905ac83f73f7aedf2f0cb4a0da7e35efa24a202a936269f1f18e1"
checksum = "d01a5bd0424d00070b0098dd17ebca6f961a959dead1dbcbbbc1d1cd8d3deeba"
[[package]]
name = "path-absolutize"
@@ -1617,9 +1651,9 @@ dependencies = [
[[package]]
name = "proc-macro2"
version = "1.0.47"
version = "1.0.49"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725"
checksum = "57a8eca9f9c4ffde41714334dee777596264c7825420f521abc92b5b5deb63a5"
dependencies = [
"unicode-ident",
]
@@ -1649,9 +1683,9 @@ dependencies = [
[[package]]
name = "quote"
version = "1.0.21"
version = "1.0.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179"
checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b"
dependencies = [
"proc-macro2",
]
@@ -1745,11 +1779,10 @@ dependencies = [
[[package]]
name = "rayon"
version = "1.6.0"
version = "1.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e060280438193c554f654141c9ea9417886713b7acd75974c85b18a69a88e0b"
checksum = "6db3a213adf02b3bcfd2d3846bb41cb22857d131789e01df434fb7e7bc0759b7"
dependencies = [
"crossbeam-deque",
"either",
"rayon-core",
]
@@ -1845,7 +1878,7 @@ dependencies = [
[[package]]
name = "ruff"
version = "0.0.190"
version = "0.0.199"
dependencies = [
"annotate-snippets 0.9.1",
"anyhow",
@@ -1854,12 +1887,15 @@ dependencies = [
"bincode",
"bitflags",
"cachedir",
"cfg-if 1.0.0",
"chrono",
"clap 4.0.29",
"clap 4.0.32",
"clap_complete_command",
"clearscreen",
"colored",
"common-path",
"console_error_panic_hook",
"console_log",
"criterion",
"dirs 4.0.0",
"fern",
@@ -1870,8 +1906,10 @@ dependencies = [
"ignore",
"insta",
"itertools",
"js-sys",
"libcst",
"log",
"natord",
"nohash-hasher",
"notify",
"num-bigint",
@@ -1886,8 +1924,13 @@ dependencies = [
"rustpython-ast",
"rustpython-common",
"rustpython-parser",
"schemars",
"semver",
"serde",
"serde-wasm-bindgen",
"serde_json",
"shellexpand",
"similar",
"strum",
"strum_macros",
"test-case",
@@ -1897,14 +1940,16 @@ dependencies = [
"update-informer",
"ureq",
"walkdir",
"wasm-bindgen",
"wasm-bindgen-test",
]
[[package]]
name = "ruff_dev"
version = "0.0.190"
version = "0.0.199"
dependencies = [
"anyhow",
"clap 4.0.29",
"clap 4.0.32",
"codegen",
"itertools",
"libcst",
@@ -1913,13 +1958,16 @@ dependencies = [
"rustpython-ast",
"rustpython-common",
"rustpython-parser",
"schemars",
"serde_json",
"strum",
"strum_macros",
"textwrap",
]
[[package]]
name = "ruff_macros"
version = "0.0.190"
version = "0.0.199"
dependencies = [
"proc-macro2",
"quote",
@@ -1935,9 +1983,9 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
[[package]]
name = "rustix"
version = "0.36.4"
version = "0.36.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb93e85278e08bb5788653183213d3a60fc242b10cb9be96586f5a73dcb67c23"
checksum = "a3807b5d10909833d3e9acd1eb5fb988f79376ff10fce42937de71a449c4c588"
dependencies = [
"bitflags",
"errno",
@@ -1962,7 +2010,7 @@ dependencies = [
[[package]]
name = "rustpython-ast"
version = "0.1.0"
source = "git+https://github.com/RustPython/RustPython.git?rev=c01f014b1269eedcf4bdb45d5fbc62ae2beecf31#c01f014b1269eedcf4bdb45d5fbc62ae2beecf31"
source = "git+https://github.com/RustPython/RustPython.git?rev=68d26955b3e24198a150315e7959719b03709dee#68d26955b3e24198a150315e7959719b03709dee"
dependencies = [
"num-bigint",
"rustpython-common",
@@ -1972,7 +2020,7 @@ dependencies = [
[[package]]
name = "rustpython-common"
version = "0.0.0"
source = "git+https://github.com/RustPython/RustPython.git?rev=c01f014b1269eedcf4bdb45d5fbc62ae2beecf31#c01f014b1269eedcf4bdb45d5fbc62ae2beecf31"
source = "git+https://github.com/RustPython/RustPython.git?rev=68d26955b3e24198a150315e7959719b03709dee#68d26955b3e24198a150315e7959719b03709dee"
dependencies = [
"ascii",
"cfg-if 1.0.0",
@@ -1995,7 +2043,7 @@ dependencies = [
[[package]]
name = "rustpython-compiler-core"
version = "0.1.2"
source = "git+https://github.com/RustPython/RustPython.git?rev=c01f014b1269eedcf4bdb45d5fbc62ae2beecf31#c01f014b1269eedcf4bdb45d5fbc62ae2beecf31"
source = "git+https://github.com/RustPython/RustPython.git?rev=68d26955b3e24198a150315e7959719b03709dee#68d26955b3e24198a150315e7959719b03709dee"
dependencies = [
"bincode",
"bitflags",
@@ -2012,7 +2060,7 @@ dependencies = [
[[package]]
name = "rustpython-parser"
version = "0.1.2"
source = "git+https://github.com/RustPython/RustPython.git?rev=c01f014b1269eedcf4bdb45d5fbc62ae2beecf31#c01f014b1269eedcf4bdb45d5fbc62ae2beecf31"
source = "git+https://github.com/RustPython/RustPython.git?rev=68d26955b3e24198a150315e7959719b03709dee#68d26955b3e24198a150315e7959719b03709dee"
dependencies = [
"ahash",
"anyhow",
@@ -2036,15 +2084,15 @@ dependencies = [
[[package]]
name = "rustversion"
version = "1.0.9"
version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97477e48b4cf8603ad5f7aaf897467cf42ab4218a38ef76fb14c2d6773a6d6a8"
checksum = "5583e89e108996506031660fe09baa5011b9dd0341b89029313006d1fb508d70"
[[package]]
name = "ryu"
version = "1.0.11"
version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09"
checksum = "7b4b9743ed687d4b4bcedf9ff5eaa7398495ae14e61cba0a295704edbc7decde"
[[package]]
name = "same-file"
@@ -2055,6 +2103,36 @@ dependencies = [
"winapi-util",
]
[[package]]
name = "schemars"
version = "0.8.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2a5fb6c61f29e723026dc8e923d94c694313212abbecbbe5f55a7748eec5b307"
dependencies = [
"dyn-clone",
"schemars_derive",
"serde",
"serde_json",
]
[[package]]
name = "schemars_derive"
version = "0.8.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f188d036977451159430f3b8dc82ec76364a42b7e289c2b18a9a18f4470058e9"
dependencies = [
"proc-macro2",
"quote",
"serde_derive_internals",
"syn",
]
[[package]]
name = "scoped-tls"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294"
[[package]]
name = "scopeguard"
version = "1.1.0"
@@ -2063,9 +2141,9 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]]
name = "scratch"
version = "1.0.2"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8132065adcfd6e02db789d9285a0deb2f3fcb04002865ab67d5fb103533898"
checksum = "ddccb15bcce173023b3fedd9436f882a0739b8dfb45e4f6b6002bee5929f61b2"
[[package]]
name = "sct"
@@ -2079,24 +2157,46 @@ dependencies = [
[[package]]
name = "semver"
version = "1.0.14"
version = "1.0.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e25dfac463d778e353db5be2449d1cce89bd6fd23c9f1ea21310ce6e5a1b29c4"
checksum = "58bc9567378fc7690d6b2addae4e60ac2eeea07becb2c64b9f218b53865cba2a"
[[package]]
name = "serde"
version = "1.0.148"
version = "1.0.151"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e53f64bb4ba0191d6d0676e1b141ca55047d83b74f5607e6d8eb88126c52c2dc"
checksum = "97fed41fc1a24994d044e6db6935e69511a1153b52c15eb42493b26fa87feba0"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.148"
name = "serde-wasm-bindgen"
version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a55492425aa53521babf6137309e7d34c20bbfbbfcfe2c7f3a047fd1f6b92c0c"
checksum = "e3b4c031cd0d9014307d82b8abf653c0290fbdaeb4c02d00c63cf52f728628bf"
dependencies = [
"js-sys",
"serde",
"wasm-bindgen",
]
[[package]]
name = "serde_derive"
version = "1.0.151"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "255abe9a125a985c05190d687b320c12f9b1f0b99445e608c21ba0782c719ad8"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "serde_derive_internals"
version = "0.26.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85bf8229e7920a9f636479437026331ce11aa132b4dde37d121944a44d6e5f3c"
dependencies = [
"proc-macro2",
"quote",
@@ -2105,15 +2205,24 @@ dependencies = [
[[package]]
name = "serde_json"
version = "1.0.89"
version = "1.0.91"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "020ff22c755c2ed3f8cf162dbb41a7268d934702f3ed3631656ea597e08fc3db"
checksum = "877c235533714907a8c2464236f5c4b2a17262ef1bd71f38f35ea592c8da6883"
dependencies = [
"itoa",
"ryu",
"serde",
]
[[package]]
name = "shellexpand"
version = "3.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd1c7ddea665294d484c39fd0c0d2b7e35bbfe10035c5fe1854741a57f6880e1"
dependencies = [
"dirs 4.0.0",
]
[[package]]
name = "similar"
version = "2.2.1"
@@ -2152,9 +2261,9 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
[[package]]
name = "str_indices"
version = "0.4.0"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d9199fa80c817e074620be84374a520062ebac833f358d74b37060ce4a0f2c0"
checksum = "5f026164926842ec52deb1938fae44f83dfdb82d0a5b0270c5bd5935ab74d6dd"
[[package]]
name = "string_cache"
@@ -2199,9 +2308,9 @@ dependencies = [
[[package]]
name = "syn"
version = "1.0.105"
version = "1.0.107"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60b9b43d45702de4c839cb9b51d9f529c5dd26a4aff255b42b1ebc03e88ee908"
checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5"
dependencies = [
"proc-macro2",
"quote",
@@ -2306,18 +2415,18 @@ dependencies = [
[[package]]
name = "thiserror"
version = "1.0.37"
version = "1.0.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "10deb33631e3c9018b9baf9dcbbc4f737320d2b576bac10f6aefa048fa407e3e"
checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.37"
version = "1.0.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb"
checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f"
dependencies = [
"proc-macro2",
"quote",
@@ -2391,9 +2500,9 @@ dependencies = [
[[package]]
name = "toml"
version = "0.5.9"
version = "0.5.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7"
checksum = "1333c76748e868a4d9d1017b5ab53171dfd095f70c712fdb4653a406547f598f"
dependencies = [
"serde",
]
@@ -2480,9 +2589,9 @@ checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992"
[[package]]
name = "unicode-ident"
version = "1.0.5"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3"
checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc"
[[package]]
name = "unicode-linebreak"
@@ -2651,6 +2760,18 @@ dependencies = [
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-futures"
version = "0.4.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23639446165ca5a5de86ae1d8896b737ae80319560fbaa4c2887b7da6e7ebd7d"
dependencies = [
"cfg-if 1.0.0",
"js-sys",
"wasm-bindgen",
"web-sys",
]
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.83"
@@ -2680,6 +2801,30 @@ version = "0.2.83"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f"
[[package]]
name = "wasm-bindgen-test"
version = "0.3.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09d2fff962180c3fadf677438054b1db62bee4aa32af26a45388af07d1287e1d"
dependencies = [
"console_error_panic_hook",
"js-sys",
"scoped-tls",
"wasm-bindgen",
"wasm-bindgen-futures",
"wasm-bindgen-test-macro",
]
[[package]]
name = "wasm-bindgen-test-macro"
version = "0.3.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4683da3dfc016f704c9f82cf401520c4f1cb3ee440f7f52b3d6ac29506a49ca7"
dependencies = [
"proc-macro2",
"quote",
]
[[package]]
name = "web-sys"
version = "0.3.60"
@@ -2702,9 +2847,9 @@ dependencies = [
[[package]]
name = "webpki-roots"
version = "0.22.5"
version = "0.22.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "368bfe657969fb01238bb756d351dcade285e0f6fcbd36dcb23359a5169975be"
checksum = "b6c71e40d7d2c34a5106301fb632274ca37242cd0c9d3e64dbece371a40a2d87"
dependencies = [
"webpki",
]

View File

@@ -6,12 +6,19 @@ members = [
[package]
name = "ruff"
version = "0.0.190"
version = "0.0.199"
authors = ["Charlie Marsh <charlie.r.marsh@gmail.com>"]
edition = "2021"
rust-version = "1.65.0"
documentation = "https://github.com/charliermarsh/ruff"
homepage = "https://github.com/charliermarsh/ruff"
repository = "https://github.com/charliermarsh/ruff"
readme = "README.md"
license = "MIT"
[lib]
name = "ruff"
crate-type = ["cdylib", "rlib"]
[dependencies]
annotate-snippets = { version = "0.9.1", features = ["color"] }
@@ -20,9 +27,10 @@ atty = { version = "0.2.14" }
bincode = { version = "1.3.3" }
bitflags = { version = "1.3.2" }
cachedir = { version = "0.3.0" }
cfg-if = { version = "1.0.0" }
chrono = { version = "0.4.21", default-features = false, features = ["clock"] }
clap = { version = "4.0.1", features = ["derive"] }
clap_complete_command = "0.4.0"
clap_complete_command = { version = "0.4.0" }
colored = { version = "2.0.0" }
common-path = { version = "1.0.0" }
dirs = { version = "4.0.0" }
@@ -34,44 +42,57 @@ ignore = { version = "0.4.18" }
itertools = { version = "0.10.5" }
libcst = { git = "https://github.com/charliermarsh/LibCST", rev = "f2f0b7a487a8725d161fe8b3ed73a6758b21e177" }
log = { version = "0.4.17" }
natord = { version = "1.0.9" }
nohash-hasher = { version = "0.2.0" }
notify = { version = "5.0.0" }
num-bigint = { version = "0.4.3" }
once_cell = { version = "1.16.0" }
path-absolutize = { version = "3.0.14", features = ["once_cell_cache", "use_unix_paths_on_wasm"] }
quick-junit = { version = "0.3.2" }
rayon = { version = "1.5.3" }
regex = { version = "1.6.0" }
ropey = { version = "1.5.0", features = ["cr_lines", "simd"], default-features = false }
ruff_macros = { version = "0.0.190", path = "ruff_macros" }
ruff_macros = { version = "0.0.199", path = "ruff_macros" }
rustc-hash = { version = "1.1.0" }
rustpython-ast = { features = ["unparse"], git = "https://github.com/RustPython/RustPython.git", rev = "c01f014b1269eedcf4bdb45d5fbc62ae2beecf31" }
rustpython-common = { git = "https://github.com/RustPython/RustPython.git", rev = "c01f014b1269eedcf4bdb45d5fbc62ae2beecf31" }
rustpython-parser = { features = ["lalrpop"], git = "https://github.com/RustPython/RustPython.git", rev = "c01f014b1269eedcf4bdb45d5fbc62ae2beecf31" }
rustpython-ast = { features = ["unparse"], git = "https://github.com/RustPython/RustPython.git", rev = "68d26955b3e24198a150315e7959719b03709dee" }
rustpython-common = { git = "https://github.com/RustPython/RustPython.git", rev = "68d26955b3e24198a150315e7959719b03709dee" }
rustpython-parser = { features = ["lalrpop"], git = "https://github.com/RustPython/RustPython.git", rev = "68d26955b3e24198a150315e7959719b03709dee" }
schemars = { version = "0.8.11" }
semver = { version = "1.0.16" }
serde = { version = "1.0.147", features = ["derive"] }
serde_json = { version = "1.0.87" }
shellexpand = { version = "3.0.0" }
similar = { version = "2.2.1" }
strum = { version = "0.24.1", features = ["strum_macros"] }
strum_macros = { version = "0.24.3" }
textwrap = { version = "0.16.0" }
titlecase = { version = "2.2.1" }
toml = { version = "0.5.9" }
update-informer = { version = "0.5.0", default-features = false, features = ["pypi"], optional = true }
walkdir = { version = "2.3.2" }
[target.'cfg(not(target_family = "wasm"))'.dependencies]
clearscreen = { version = "1.0.10" } # uses which
clearscreen = { version = "1.0.10" }
rayon = { version = "1.5.3" }
update-informer = { version = "0.5.0", default-features = false, features = ["pypi"], optional = true }
# https://docs.rs/getrandom/0.2.7/getrandom/#webassembly-support
# For (future) wasm-pack support
[target.'cfg(all(target_family = "wasm", target_os = "unknown"))'.dependencies]
getrandom = { version = "0.2.7", features = ["js"] }
console_error_panic_hook = { version = "0.1.7" }
console_log = { version = "0.2.0" }
serde-wasm-bindgen = { version = "0.4" }
js-sys = { version = "0.3.60" }
wasm-bindgen = { version = "0.2.83" }
[dev-dependencies]
assert_cmd = { version = "2.0.4" }
criterion = { version = "0.4.0" }
insta = { version = "1.19.1", features = ["yaml"] }
test-case = { version = "2.2.2" }
ureq = { version = "2.5.0", features = [] }
wasm-bindgen-test = { version = "0.3.33" }
[target.'cfg(not(target_family = "wasm"))'.dev-dependencies]
assert_cmd = { version = "2.0.4" }
criterion = { version = "0.4.0" }
[features]
default = ["update-informer"]
@@ -89,6 +110,11 @@ opt-level = 3
[profile.dev.package.similar]
opt-level = 3
# Reduce complexity of a parser function that would trigger a locals limit in a wasm tool.
# https://github.com/bytecodealliance/wasm-tools/blob/b5c3d98e40590512a3b12470ef358d5c7b983b15/crates/wasmparser/src/limits.rs#L29
[profile.dev.package.rustpython-parser]
opt-level = 1
[[bench]]
name = "source_code_locator"
harness = false

580
README.md

File diff suppressed because it is too large Load Diff

View File

@@ -771,7 +771,7 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
[[package]]
name = "flake8_to_ruff"
version = "0.0.190"
version = "0.0.199"
dependencies = [
"anyhow",
"clap",
@@ -1975,7 +1975,7 @@ dependencies = [
[[package]]
name = "ruff"
version = "0.0.190"
version = "0.0.199"
dependencies = [
"anyhow",
"bincode",
@@ -2028,7 +2028,7 @@ dependencies = [
[[package]]
name = "rustpython-ast"
version = "0.1.0"
source = "git+https://github.com/RustPython/RustPython.git?rev=c01f014b1269eedcf4bdb45d5fbc62ae2beecf31#c01f014b1269eedcf4bdb45d5fbc62ae2beecf31"
source = "git+https://github.com/RustPython/RustPython.git?rev=1b6cb170e925a43d605b3fed9f6b878e63e47744#1b6cb170e925a43d605b3fed9f6b878e63e47744"
dependencies = [
"num-bigint",
"rustpython-common",
@@ -2038,7 +2038,7 @@ dependencies = [
[[package]]
name = "rustpython-common"
version = "0.0.0"
source = "git+https://github.com/RustPython/RustPython.git?rev=c01f014b1269eedcf4bdb45d5fbc62ae2beecf31#c01f014b1269eedcf4bdb45d5fbc62ae2beecf31"
source = "git+https://github.com/RustPython/RustPython.git?rev=1b6cb170e925a43d605b3fed9f6b878e63e47744#1b6cb170e925a43d605b3fed9f6b878e63e47744"
dependencies = [
"ascii",
"cfg-if 1.0.0",
@@ -2061,7 +2061,7 @@ dependencies = [
[[package]]
name = "rustpython-compiler-core"
version = "0.1.2"
source = "git+https://github.com/RustPython/RustPython.git?rev=c01f014b1269eedcf4bdb45d5fbc62ae2beecf31#c01f014b1269eedcf4bdb45d5fbc62ae2beecf31"
source = "git+https://github.com/RustPython/RustPython.git?rev=1b6cb170e925a43d605b3fed9f6b878e63e47744#1b6cb170e925a43d605b3fed9f6b878e63e47744"
dependencies = [
"bincode",
"bitflags",
@@ -2078,7 +2078,7 @@ dependencies = [
[[package]]
name = "rustpython-parser"
version = "0.1.2"
source = "git+https://github.com/RustPython/RustPython.git?rev=c01f014b1269eedcf4bdb45d5fbc62ae2beecf31#c01f014b1269eedcf4bdb45d5fbc62ae2beecf31"
source = "git+https://github.com/RustPython/RustPython.git?rev=1b6cb170e925a43d605b3fed9f6b878e63e47744#1b6cb170e925a43d605b3fed9f6b878e63e47744"
dependencies = [
"ahash",
"anyhow",

View File

@@ -1,6 +1,6 @@
[package]
name = "flake8-to-ruff"
version = "0.0.190-dev.0"
version = "0.0.199-dev.0"
edition = "2021"
[lib]
@@ -16,6 +16,8 @@ ruff = { path = "..", default-features = false }
rustc-hash = { version = "1.1.0" }
serde = { version = "1.0.147", features = ["derive"] }
serde_json = { version = "1.0.87" }
strum = { version = "0.24.1", features = ["strum_macros"] }
strum_macros = { version = "0.24.3" }
toml = { version = "0.5.9" }
[dev-dependencies]

View File

@@ -0,0 +1,65 @@
[build-system]
requires = [
# The minimum setuptools version is specific to the PEP 517 backend,
# and may be stricter than the version required in `setup.cfg`
"setuptools>=40.6.0,!=60.9.0",
"wheel",
# Must be kept in sync with the `install_requirements` in `setup.cfg`
"cffi>=1.12; platform_python_implementation != 'PyPy'",
"setuptools-rust>=0.11.4",
]
build-backend = "setuptools.build_meta"
[tool.black]
line-length = 79
target-version = ["py36"]
[tool.pytest.ini_options]
addopts = "-r s --capture=no --strict-markers --benchmark-disable"
markers = [
"skip_fips: this test is not executed in FIPS mode",
"supported: parametrized test requiring only_if and skip_message",
]
[tool.mypy]
show_error_codes = true
check_untyped_defs = true
no_implicit_reexport = true
warn_redundant_casts = true
warn_unused_ignores = true
warn_unused_configs = true
strict_equality = true
[[tool.mypy.overrides]]
module = [
"pretend"
]
ignore_missing_imports = true
[tool.coverage.run]
branch = true
relative_files = true
source = [
"cryptography",
"tests/",
]
[tool.coverage.paths]
source = [
"src/cryptography",
"*.tox/*/lib*/python*/site-packages/cryptography",
"*.tox\\*\\Lib\\site-packages\\cryptography",
"*.tox/pypy/site-packages/cryptography",
]
tests =[
"tests/",
"*tests\\",
]
[tool.coverage.report]
exclude_lines = [
"@abc.abstractmethod",
"@abc.abstractproperty",
"@typing.overload",
"if typing.TYPE_CHECKING",
]

View File

@@ -0,0 +1,91 @@
[metadata]
name = cryptography
version = attr: cryptography.__version__
description = cryptography is a package which provides cryptographic recipes and primitives to Python developers.
long_description = file: README.rst
long_description_content_type = text/x-rst
license = BSD-3-Clause OR Apache-2.0
url = https://github.com/pyca/cryptography
author = The Python Cryptographic Authority and individual contributors
author_email = cryptography-dev@python.org
project_urls =
Documentation=https://cryptography.io/
Source=https://github.com/pyca/cryptography/
Issues=https://github.com/pyca/cryptography/issues
Changelog=https://cryptography.io/en/latest/changelog/
classifiers =
Development Status :: 5 - Production/Stable
Intended Audience :: Developers
License :: OSI Approved :: Apache Software License
License :: OSI Approved :: BSD License
Natural Language :: English
Operating System :: MacOS :: MacOS X
Operating System :: POSIX
Operating System :: POSIX :: BSD
Operating System :: POSIX :: Linux
Operating System :: Microsoft :: Windows
Programming Language :: Python
Programming Language :: Python :: 3
Programming Language :: Python :: 3 :: Only
Programming Language :: Python :: 3.6
Programming Language :: Python :: 3.7
Programming Language :: Python :: 3.8
Programming Language :: Python :: 3.9
Programming Language :: Python :: 3.10
Programming Language :: Python :: 3.11
Programming Language :: Python :: Implementation :: CPython
Programming Language :: Python :: Implementation :: PyPy
Topic :: Security :: Cryptography
[options]
python_requires = >=3.6
include_package_data = True
zip_safe = False
package_dir =
=src
packages = find:
# `install_requires` must be kept in sync with `pyproject.toml`
install_requires =
cffi >=1.12
[options.packages.find]
where = src
exclude =
_cffi_src
_cffi_src.*
[options.extras_require]
test =
pytest>=6.2.0
pytest-benchmark
pytest-cov
pytest-subtests
pytest-xdist
pretend
iso8601
pytz
hypothesis>=1.11.4,!=3.79.2
docs =
sphinx >= 1.6.5,!=1.8.0,!=3.1.0,!=3.1.1,!=5.2.0,!=5.2.0.post0
sphinx_rtd_theme
docstest =
pyenchant >= 1.6.11
twine >= 1.12.0
sphinxcontrib-spelling >= 4.0.1
sdist =
setuptools_rust >= 0.11.4
pep8test =
black
flake8
flake8-import-order
pep8-naming
# This extra is for OpenSSH private keys that use bcrypt KDF
# Versions: v3.1.3 - ignore_few_rounds, v3.1.5 - abi3
ssh =
bcrypt >= 3.1.5
[flake8]
ignore = E203,E211,W503,W504,N818
exclude = .tox,*.egg,.git,_build,.hypothesis
select = E,W,F,N,I
application-import-names = cryptography,cryptography_vectors,tests

View File

@@ -12,6 +12,7 @@ classifiers = [
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3 :: Only",
"Topic :: Software Development :: Libraries :: Python Modules",
"Topic :: Software Development :: Quality Assurance",

View File

@@ -0,0 +1,32 @@
//! Extract Black configuration settings from a pyproject.toml.
use std::path::Path;
use anyhow::Result;
use ruff::settings::types::PythonVersion;
use serde::{Deserialize, Serialize};
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Default)]
pub struct Black {
#[serde(alias = "line-length", alias = "line_length")]
pub line_length: Option<usize>,
#[serde(alias = "target-version", alias = "target_version")]
pub target_version: Option<Vec<PythonVersion>>,
}
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
struct Tools {
black: Option<Black>,
}
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
struct Pyproject {
tool: Option<Tools>,
}
pub fn parse_black_options<P: AsRef<Path>>(path: P) -> Result<Option<Black>> {
let contents = std::fs::read_to_string(path)?;
Ok(toml::from_str::<Pyproject>(&contents)?
.tool
.and_then(|tool| tool.black))
}

View File

@@ -4,20 +4,28 @@ use anyhow::Result;
use ruff::checks_gen::CheckCodePrefix;
use ruff::flake8_quotes::settings::Quote;
use ruff::flake8_tidy_imports::settings::Strictness;
use ruff::pydocstyle::settings::Convention;
use ruff::settings::options::Options;
use ruff::settings::pyproject::Pyproject;
use ruff::{
flake8_annotations, flake8_bugbear, flake8_errmsg, flake8_quotes, flake8_tidy_imports, mccabe,
pep8_naming,
pep8_naming, pydocstyle,
};
use crate::black::Black;
use crate::plugin::Plugin;
use crate::{parser, plugin};
pub fn convert(
flake8: &HashMap<String, Option<String>>,
config: &HashMap<String, HashMap<String, Option<String>>>,
black: Option<&Black>,
plugins: Option<Vec<Plugin>>,
) -> Result<Pyproject> {
// Extract the Flake8 section.
let flake8 = config
.get("flake8")
.expect("Unable to find flake8 section in INI file");
// Extract all referenced check code prefixes, to power plugin inference.
let mut referenced_codes: BTreeSet<CheckCodePrefix> = BTreeSet::default();
for (key, value) in flake8 {
@@ -54,10 +62,15 @@ pub fn convert(
plugin::resolve_select(
flake8,
&plugins.unwrap_or_else(|| {
plugin::infer_plugins_from_options(flake8)
.into_iter()
.chain(plugin::infer_plugins_from_codes(&referenced_codes))
.collect()
let from_options = plugin::infer_plugins_from_options(flake8);
if !from_options.is_empty() {
eprintln!("Inferred plugins from settings: {from_options:#?}");
}
let from_codes = plugin::infer_plugins_from_codes(&referenced_codes);
if !from_codes.is_empty() {
eprintln!("Inferred plugins from referenced check codes: {from_codes:#?}");
}
from_options.into_iter().chain(from_codes).collect()
}),
)
});
@@ -79,6 +92,7 @@ pub fn convert(
let mut flake8_tidy_imports = flake8_tidy_imports::settings::Options::default();
let mut mccabe = mccabe::settings::Options::default();
let mut pep8_naming = pep8_naming::settings::Options::default();
let mut pydocstyle = pydocstyle::settings::Options::default();
for (key, value) in flake8 {
if let Some(value) = value {
match key.as_str() {
@@ -188,9 +202,12 @@ pub fn convert(
_ => eprintln!("Unexpected '{key}' value: {value}"),
},
// flake8-docstrings
"docstring-convention" => {
// No-op (handled above).
}
"docstring-convention" => match value.trim() {
"google" => pydocstyle.convention = Some(Convention::Google),
"numpy" => pydocstyle.convention = Some(Convention::Numpy),
"pep257" | "all" => pydocstyle.convention = None,
_ => eprintln!("Unexpected '{key}' value: {value}"),
},
// mccabe
"max-complexity" | "max_complexity" => match value.clone().parse::<usize>() {
Ok(max_complexity) => mccabe.max_complexity = Some(max_complexity),
@@ -235,6 +252,22 @@ pub fn convert(
if pep8_naming != pep8_naming::settings::Options::default() {
options.pep8_naming = Some(pep8_naming);
}
if pydocstyle != pydocstyle::settings::Options::default() {
options.pydocstyle = Some(pydocstyle);
}
// Extract any settings from the existing `pyproject.toml`.
if let Some(black) = black {
if let Some(line_length) = &black.line_length {
options.line_length = Some(*line_length);
}
if let Some(target_version) = &black.target_version {
if let Some(target_version) = target_version.iter().min() {
options.target_version = Some(*target_version);
}
}
}
// Create the pyproject.toml.
Ok(Pyproject::new(options))
@@ -246,16 +279,21 @@ mod tests {
use anyhow::Result;
use ruff::checks_gen::CheckCodePrefix;
use ruff::flake8_quotes;
use ruff::pydocstyle::settings::Convention;
use ruff::settings::options::Options;
use ruff::settings::pyproject::Pyproject;
use ruff::{flake8_quotes, pydocstyle};
use crate::converter::convert;
use crate::plugin::Plugin;
#[test]
fn it_converts_empty() -> Result<()> {
let actual = convert(&HashMap::from([]), None)?;
let actual = convert(
&HashMap::from([("flake8".to_string(), HashMap::default())]),
None,
None,
)?;
let expected = Pyproject::new(Options {
allowed_confusables: None,
dummy_variable_rgx: None,
@@ -266,6 +304,7 @@ mod tests {
extend_select: None,
external: None,
fix: None,
fix_only: None,
fixable: None,
format: None,
force_exclude: None,
@@ -273,6 +312,7 @@ mod tests {
ignore_init_module_imports: None,
line_length: None,
per_file_ignores: None,
required_version: None,
respect_gitignore: None,
select: Some(vec![
CheckCodePrefix::E,
@@ -283,6 +323,7 @@ mod tests {
src: None,
target_version: None,
unfixable: None,
cache_dir: None,
flake8_annotations: None,
flake8_bugbear: None,
flake8_errmsg: None,
@@ -293,6 +334,7 @@ mod tests {
isort: None,
mccabe: None,
pep8_naming: None,
pydocstyle: None,
pyupgrade: None,
});
assert_eq!(actual, expected);
@@ -303,7 +345,11 @@ mod tests {
#[test]
fn it_converts_dashes() -> Result<()> {
let actual = convert(
&HashMap::from([("max-line-length".to_string(), Some("100".to_string()))]),
&HashMap::from([(
"flake8".to_string(),
HashMap::from([("max-line-length".to_string(), Some("100".to_string()))]),
)]),
None,
Some(vec![]),
)?;
let expected = Pyproject::new(Options {
@@ -316,6 +362,7 @@ mod tests {
extend_select: None,
external: None,
fix: None,
fix_only: None,
fixable: None,
format: None,
force_exclude: None,
@@ -323,6 +370,7 @@ mod tests {
ignore_init_module_imports: None,
line_length: Some(100),
per_file_ignores: None,
required_version: None,
respect_gitignore: None,
select: Some(vec![
CheckCodePrefix::E,
@@ -333,6 +381,7 @@ mod tests {
src: None,
target_version: None,
unfixable: None,
cache_dir: None,
flake8_annotations: None,
flake8_bugbear: None,
flake8_errmsg: None,
@@ -343,6 +392,7 @@ mod tests {
isort: None,
mccabe: None,
pep8_naming: None,
pydocstyle: None,
pyupgrade: None,
});
assert_eq!(actual, expected);
@@ -353,7 +403,11 @@ mod tests {
#[test]
fn it_converts_underscores() -> Result<()> {
let actual = convert(
&HashMap::from([("max_line_length".to_string(), Some("100".to_string()))]),
&HashMap::from([(
"flake8".to_string(),
HashMap::from([("max_line_length".to_string(), Some("100".to_string()))]),
)]),
None,
Some(vec![]),
)?;
let expected = Pyproject::new(Options {
@@ -366,6 +420,7 @@ mod tests {
extend_select: None,
external: None,
fix: None,
fix_only: None,
fixable: None,
format: None,
force_exclude: None,
@@ -373,6 +428,7 @@ mod tests {
ignore_init_module_imports: None,
line_length: Some(100),
per_file_ignores: None,
required_version: None,
respect_gitignore: None,
select: Some(vec![
CheckCodePrefix::E,
@@ -383,6 +439,7 @@ mod tests {
src: None,
target_version: None,
unfixable: None,
cache_dir: None,
flake8_annotations: None,
flake8_bugbear: None,
flake8_errmsg: None,
@@ -393,6 +450,7 @@ mod tests {
isort: None,
mccabe: None,
pep8_naming: None,
pydocstyle: None,
pyupgrade: None,
});
assert_eq!(actual, expected);
@@ -403,7 +461,11 @@ mod tests {
#[test]
fn it_ignores_parse_errors() -> Result<()> {
let actual = convert(
&HashMap::from([("max_line_length".to_string(), Some("abc".to_string()))]),
&HashMap::from([(
"flake8".to_string(),
HashMap::from([("max_line_length".to_string(), Some("abc".to_string()))]),
)]),
None,
Some(vec![]),
)?;
let expected = Pyproject::new(Options {
@@ -416,6 +478,7 @@ mod tests {
extend_select: None,
external: None,
fix: None,
fix_only: None,
fixable: None,
format: None,
force_exclude: None,
@@ -423,6 +486,7 @@ mod tests {
ignore_init_module_imports: None,
line_length: None,
per_file_ignores: None,
required_version: None,
respect_gitignore: None,
select: Some(vec![
CheckCodePrefix::E,
@@ -433,6 +497,7 @@ mod tests {
src: None,
target_version: None,
unfixable: None,
cache_dir: None,
flake8_annotations: None,
flake8_bugbear: None,
flake8_errmsg: None,
@@ -443,6 +508,7 @@ mod tests {
isort: None,
mccabe: None,
pep8_naming: None,
pydocstyle: None,
pyupgrade: None,
});
assert_eq!(actual, expected);
@@ -453,7 +519,11 @@ mod tests {
#[test]
fn it_converts_plugin_options() -> Result<()> {
let actual = convert(
&HashMap::from([("inline-quotes".to_string(), Some("single".to_string()))]),
&HashMap::from([(
"flake8".to_string(),
HashMap::from([("inline-quotes".to_string(), Some("single".to_string()))]),
)]),
None,
Some(vec![]),
)?;
let expected = Pyproject::new(Options {
@@ -466,6 +536,7 @@ mod tests {
extend_select: None,
external: None,
fix: None,
fix_only: None,
fixable: None,
format: None,
force_exclude: None,
@@ -473,6 +544,7 @@ mod tests {
ignore_init_module_imports: None,
line_length: None,
per_file_ignores: None,
required_version: None,
respect_gitignore: None,
select: Some(vec![
CheckCodePrefix::E,
@@ -483,6 +555,7 @@ mod tests {
src: None,
target_version: None,
unfixable: None,
cache_dir: None,
flake8_annotations: None,
flake8_bugbear: None,
flake8_errmsg: None,
@@ -498,6 +571,7 @@ mod tests {
isort: None,
mccabe: None,
pep8_naming: None,
pydocstyle: None,
pyupgrade: None,
});
assert_eq!(actual, expected);
@@ -509,9 +583,13 @@ mod tests {
fn it_converts_docstring_conventions() -> Result<()> {
let actual = convert(
&HashMap::from([(
"docstring-convention".to_string(),
Some("numpy".to_string()),
"flake8".to_string(),
HashMap::from([(
"docstring-convention".to_string(),
Some("numpy".to_string()),
)]),
)]),
None,
Some(vec![Plugin::Flake8Docstrings]),
)?;
let expected = Pyproject::new(Options {
@@ -524,6 +602,7 @@ mod tests {
extend_select: None,
external: None,
fix: None,
fix_only: None,
fixable: None,
format: None,
force_exclude: None,
@@ -531,6 +610,7 @@ mod tests {
ignore_init_module_imports: None,
line_length: None,
per_file_ignores: None,
required_version: None,
respect_gitignore: None,
select: Some(vec![
CheckCodePrefix::D100,
@@ -577,6 +657,7 @@ mod tests {
src: None,
target_version: None,
unfixable: None,
cache_dir: None,
flake8_annotations: None,
flake8_bugbear: None,
flake8_errmsg: None,
@@ -587,6 +668,9 @@ mod tests {
isort: None,
mccabe: None,
pep8_naming: None,
pydocstyle: Some(pydocstyle::settings::Options {
convention: Some(Convention::Numpy),
}),
pyupgrade: None,
});
assert_eq!(actual, expected);
@@ -597,7 +681,11 @@ mod tests {
#[test]
fn it_infers_plugins_if_omitted() -> Result<()> {
let actual = convert(
&HashMap::from([("inline-quotes".to_string(), Some("single".to_string()))]),
&HashMap::from([(
"flake8".to_string(),
HashMap::from([("inline-quotes".to_string(), Some("single".to_string()))]),
)]),
None,
None,
)?;
let expected = Pyproject::new(Options {
@@ -610,6 +698,7 @@ mod tests {
extend_select: None,
external: None,
fix: None,
fix_only: None,
fixable: None,
format: None,
force_exclude: None,
@@ -617,6 +706,7 @@ mod tests {
ignore_init_module_imports: None,
line_length: None,
per_file_ignores: None,
required_version: None,
respect_gitignore: None,
select: Some(vec![
CheckCodePrefix::E,
@@ -628,6 +718,7 @@ mod tests {
src: None,
target_version: None,
unfixable: None,
cache_dir: None,
flake8_annotations: None,
flake8_bugbear: None,
flake8_errmsg: None,
@@ -643,6 +734,7 @@ mod tests {
isort: None,
mccabe: None,
pep8_naming: None,
pydocstyle: None,
pyupgrade: None,
});
assert_eq!(actual, expected);

View File

@@ -11,6 +11,7 @@
clippy::too_many_lines
)]
pub mod black;
pub mod converter;
mod parser;
pub mod plugin;

View File

@@ -17,6 +17,7 @@ use std::path::PathBuf;
use anyhow::Result;
use clap::Parser;
use configparser::ini::Ini;
use flake8_to_ruff::black::parse_black_options;
use flake8_to_ruff::converter;
use flake8_to_ruff::plugin::Plugin;
@@ -26,10 +27,14 @@ use flake8_to_ruff::plugin::Plugin;
long_about = None
)]
struct Cli {
/// Path to the Flake8 configuration file (e.g., 'setup.cfg', 'tox.ini', or
/// '.flake8').
/// Path to the Flake8 configuration file (e.g., `setup.cfg`, `tox.ini`, or
/// `.flake8`).
#[arg(required = true)]
file: PathBuf,
/// Optional path to a `pyproject.toml` file, used to ensure compatibility
/// with Black.
#[arg(long)]
pyproject: Option<PathBuf>,
/// List of plugins to enable.
#[arg(long, value_delimiter = ',')]
plugin: Option<Vec<Plugin>>,
@@ -43,13 +48,15 @@ fn main() -> Result<()> {
ini.set_multiline(true);
let config = ini.load(cli.file).map_err(|msg| anyhow::anyhow!(msg))?;
// Extract the Flake8 section.
let flake8 = config
.get("flake8")
.expect("Unable to find flake8 section in INI file");
// Read the pyproject.toml file.
let black = cli
.pyproject
.map(parse_black_options)
.transpose()?
.flatten();
// Create the pyproject.toml.
let pyproject = converter::convert(flake8, cli.plugin)?;
// Create Ruff's pyproject.toml section.
let pyproject = converter::convert(&config, black.as_ref(), cli.plugin)?;
println!("{}", toml::to_string_pretty(&pyproject)?);
Ok(())

View File

@@ -3,6 +3,7 @@ use std::str::FromStr;
use anyhow::{bail, Result};
use once_cell::sync::Lazy;
use regex::Regex;
use ruff::checks::PREFIX_REDIRECTS;
use ruff::checks_gen::CheckCodePrefix;
use ruff::settings::types::PatternPrefixPair;
use rustc_hash::FxHashMap;
@@ -18,7 +19,9 @@ pub fn parse_prefix_codes(value: &str) -> Vec<CheckCodePrefix> {
if code.is_empty() {
continue;
}
if let Ok(code) = CheckCodePrefix::from_str(code) {
if let Some(code) = PREFIX_REDIRECTS.get(code) {
codes.push(code.clone());
} else if let Ok(code) = CheckCodePrefix::from_str(code) {
codes.push(code);
} else {
eprintln!("Unsupported prefix code: {code}");
@@ -83,16 +86,22 @@ impl State {
fn parse(&self) -> Vec<PatternPrefixPair> {
let mut codes: Vec<PatternPrefixPair> = vec![];
for code in &self.codes {
match CheckCodePrefix::from_str(code) {
Ok(code) => {
for filename in &self.filenames {
codes.push(PatternPrefixPair {
pattern: filename.clone(),
prefix: code.clone(),
});
}
if let Some(code) = PREFIX_REDIRECTS.get(code.as_str()) {
for filename in &self.filenames {
codes.push(PatternPrefixPair {
pattern: filename.clone(),
prefix: code.clone(),
});
}
Err(_) => eprintln!("Skipping unrecognized prefix: {code}"),
} else if let Ok(code) = CheckCodePrefix::from_str(code) {
for filename in &self.filenames {
codes.push(PatternPrefixPair {
pattern: filename.clone(),
prefix: code.clone(),
});
}
} else {
eprintln!("Unsupported prefix code: {code}");
}
}
codes

View File

@@ -1,10 +1,11 @@
use std::collections::{BTreeSet, HashMap};
use std::fmt;
use std::str::FromStr;
use anyhow::anyhow;
use ruff::checks_gen::CheckCodePrefix;
#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq)]
#[derive(Clone, Ord, PartialOrd, Eq, PartialEq)]
pub enum Plugin {
Flake8Annotations,
Flake8Bandit,
@@ -42,7 +43,7 @@ impl FromStr for Plugin {
"flake8-datetimez" => Ok(Plugin::Flake8Datetimez),
"flake8-debugger" => Ok(Plugin::Flake8Debugger),
"flake8-docstrings" => Ok(Plugin::Flake8Docstrings),
"flake8-eradicate" => Ok(Plugin::Flake8BlindExcept),
"flake8-eradicate" => Ok(Plugin::Flake8Eradicate),
"flake8-errmsg" => Ok(Plugin::Flake8ErrMsg),
"flake8-print" => Ok(Plugin::Flake8Print),
"flake8-quotes" => Ok(Plugin::Flake8Quotes),
@@ -58,6 +59,37 @@ impl FromStr for Plugin {
}
}
impl fmt::Debug for Plugin {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"{}",
match self {
Plugin::Flake8Annotations => "flake8-annotations",
Plugin::Flake8Bandit => "flake8-bandit",
Plugin::Flake8BlindExcept => "flake8-blind-except",
Plugin::Flake8Bugbear => "flake8-bugbear",
Plugin::Flake8Builtins => "flake8-builtins",
Plugin::Flake8Comprehensions => "flake8-comprehensions",
Plugin::Flake8Datetimez => "flake8-datetimez",
Plugin::Flake8Debugger => "flake8-debugger",
Plugin::Flake8Docstrings => "flake8-docstrings",
Plugin::Flake8Eradicate => "flake8-eradicate",
Plugin::Flake8ErrMsg => "flake8-errmsg",
Plugin::Flake8Print => "flake8-print",
Plugin::Flake8Quotes => "flake8-quotes",
Plugin::Flake8Return => "flake8-return",
Plugin::Flake8Simplify => "flake8-simplify",
Plugin::Flake8TidyImports => "flake8-tidy-imports",
Plugin::McCabe => "mccabe",
Plugin::PandasVet => "pandas-vet",
Plugin::PEP8Naming => "pep8-naming",
Plugin::Pyupgrade => "pyupgrade",
}
)
}
}
impl Plugin {
pub fn default(&self) -> CheckCodePrefix {
match self {
@@ -78,11 +110,11 @@ impl Plugin {
Plugin::Flake8Quotes => CheckCodePrefix::Q,
Plugin::Flake8Return => CheckCodePrefix::RET,
Plugin::Flake8Simplify => CheckCodePrefix::SIM,
Plugin::Flake8TidyImports => CheckCodePrefix::I25,
Plugin::Flake8TidyImports => CheckCodePrefix::TID25,
Plugin::McCabe => CheckCodePrefix::C9,
Plugin::PandasVet => CheckCodePrefix::PD,
Plugin::PEP8Naming => CheckCodePrefix::N,
Plugin::Pyupgrade => CheckCodePrefix::U,
Plugin::Pyupgrade => CheckCodePrefix::UP,
}
}
@@ -424,7 +456,6 @@ pub fn infer_plugins_from_codes(codes: &BTreeSet<CheckCodePrefix>) -> Vec<Plugin
Plugin::Flake8TidyImports,
Plugin::PandasVet,
Plugin::PEP8Naming,
Plugin::Pyupgrade,
]
.into_iter()
.filter(|plugin| {

25
playground/.eslintrc Normal file
View File

@@ -0,0 +1,25 @@
{
"parser": "@typescript-eslint/parser",
"plugins": ["@typescript-eslint", "prettier"],
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/eslint-recommended",
"plugin:@typescript-eslint/recommended",
"plugin:react/recommended",
"plugin:react/jsx-runtime",
"plugin:react-hooks/recommended",
"plugin:import/recommended",
"plugin:import/typescript",
"plugin:prettier/recommended"
],
"rules": {
// Disable some recommended rules that we don't want to enforce.
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-empty-function": "off"
},
"settings": {
"react": {
"version": "detect"
}
}
}

130
playground/.gitignore vendored Normal file
View File

@@ -0,0 +1,130 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
.pnpm-debug.log*
# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
*.lcov
# nyc test coverage
.nyc_output
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# Snowpack dependency directory (https://snowpack.dev/)
web_modules/
# TypeScript cache
*.tsbuildinfo
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional stylelint cache
.stylelintcache
# Microbundle cache
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variable files
.env
.env.development.local
.env.test.local
.env.production.local
.env.local
# parcel-bundler cache (https://parceljs.org/)
.cache
.parcel-cache
# Next.js build output
.next
out
# Nuxt.js build / generate output
.nuxt
dist
# Gatsby files
.cache/
# Comment in the public line in if your project uses Gatsby and not Next.js
# https://nextjs.org/blog/next-9-1#public-directory-support
# public
# vuepress build output
.vuepress/dist
# vuepress v2.x temp and cache directory
.temp
.cache
# Docusaurus cache and generated files
.docusaurus
# Serverless directories
.serverless/
# FuseBox cache
.fusebox/
# DynamoDB Local files
.dynamodb/
# TernJS port file
.tern-port
# Stores VSCode versions used for testing VSCode extensions
.vscode-test
# yarn v2
.yarn/cache
.yarn/unplugged
.yarn/build-state.yml
.yarn/install-state.gz
.pnp.*

View File

@@ -0,0 +1 @@
src/ruff_options.ts

10
playground/README.md Normal file
View File

@@ -0,0 +1,10 @@
# playground
In-browser playground for Ruff. Available [https://ruff.pages.dev/](https://ruff.pages.dev/).
## Getting started
- To build the WASM module, run `wasm-pack build --target web --out-dir playground/src/pkg` from the
root directory.
- Install TypeScript dependencies with: `npm install`.
- Start the development server with: `npm run dev`.

29
playground/index.html Normal file
View File

@@ -0,0 +1,29 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta
name="description"
content="An in-browser playground for Ruff, an extremely fast Python linter written in Rust."
/>
<meta name="keywords" content="ruff, python, rust, webassembly, wasm" />
<title>Ruff Playground</title>
<link
rel="icon"
href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>🛠️</text></svg>"
/>
</head>
<body>
<div id="root"></div>
<div style="display: flex; position: fixed; right: 16px; top: 16px">
<a href="https://GitHub.com/charliermarsh/ruff"
><img
src="https://img.shields.io/github/stars/charliermarsh/ruff.svg?style=social&label=GitHub&maxAge=2592000&?logoWidth=100"
alt="GitHub stars"
style="width: 120px"
/></a>
</div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>

5870
playground/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

38
playground/package.json Normal file
View File

@@ -0,0 +1,38 @@
{
"name": "playground",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"build": "tsc && vite build",
"check": "npm run lint && npm run tsc",
"dev": "vite",
"fmt": "prettier --cache -w .",
"lint": "eslint --cache --ext .ts,.tsx src",
"preview": "vite preview",
"tsc": "tsc"
},
"dependencies": {
"@monaco-editor/react": "^4.4.6",
"lz-string": "^1.4.4",
"monaco-editor": "^0.34.1",
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"devDependencies": {
"@types/react": "^18.0.26",
"@types/react-dom": "^18.0.9",
"@typescript-eslint/eslint-plugin": "^5.47.1",
"@typescript-eslint/parser": "^5.47.1",
"@vitejs/plugin-react-swc": "^3.0.0",
"eslint": "^8.30.0",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-import": "^2.26.0",
"eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-react": "^7.31.11",
"eslint-plugin-react-hooks": "^4.6.0",
"prettier": "^2.8.1",
"typescript": "^4.9.3",
"vite": "^4.0.0"
}
}

200
playground/src/App.tsx Normal file
View File

@@ -0,0 +1,200 @@
import lzstring from "lz-string";
import Editor, { useMonaco } from "@monaco-editor/react";
import { MarkerSeverity } from "monaco-editor/esm/vs/editor/editor.api";
import { useEffect, useState, useCallback } from "react";
import init, { Check, check } from "./pkg/ruff.js";
import { AVAILABLE_OPTIONS } from "./ruff_options";
import { Config, getDefaultConfig, toRuffConfig } from "./config";
import { Options } from "./Options";
const DEFAULT_SOURCE =
"# Define a function that takes an integer n and returns the nth number in the Fibonacci\n" +
"# sequence.\n" +
"def fibonacci(n):\n" +
" if n == 0:\n" +
" return 0\n" +
" elif n == 1:\n" +
" return 1\n" +
" else:\n" +
" return fibonacci(n-1) + fibonacci(n-2)\n" +
"\n" +
"# Use a for loop to generate and print the first 10 numbers in the Fibonacci sequence.\n" +
"for i in range(10):\n" +
" print(fibonacci(i))\n" +
"\n" +
"# Output:\n" +
"# 0\n" +
"# 1\n" +
"# 1\n" +
"# 2\n" +
"# 3\n" +
"# 5\n" +
"# 8\n" +
"# 13\n" +
"# 21\n" +
"# 34\n";
function restoreConfigAndSource(): [Config, string] {
const value = lzstring.decompressFromEncodedURIComponent(
window.location.hash.slice(1)
);
let config = {};
let source = DEFAULT_SOURCE;
if (value) {
const parts = value.split("$$$");
config = JSON.parse(parts[0]);
source = parts[1];
}
return [config, source];
}
function persistConfigAndSource(config: Config, source: string) {
window.location.hash = lzstring.compressToEncodedURIComponent(
JSON.stringify(config) + "$$$" + source
);
}
const defaultConfig = getDefaultConfig(AVAILABLE_OPTIONS);
export default function App() {
const monaco = useMonaco();
const [initialized, setInitialized] = useState<boolean>(false);
const [config, setConfig] = useState<Config | null>(null);
const [source, setSource] = useState<string | null>(null);
const [error, setError] = useState<string | null>(null);
useEffect(() => {
init().then(() => setInitialized(true));
}, []);
useEffect(() => {
if (source == null && config == null && monaco) {
const [config, source] = restoreConfigAndSource();
setConfig(config);
setSource(source);
}
}, [monaco, source, config]);
useEffect(() => {
if (config != null && source != null) {
persistConfigAndSource(config, source);
}
}, [config, source]);
useEffect(() => {
const editor = monaco?.editor;
const model = editor?.getModels()[0];
if (!editor || !model || !initialized || source == null || config == null) {
return;
}
let checks: Check[];
try {
checks = check(source, toRuffConfig(config));
setError(null);
} catch (e) {
setError(String(e));
return;
}
editor.setModelMarkers(
model,
"owner",
checks.map((check) => ({
startLineNumber: check.location.row,
startColumn: check.location.column + 1,
endLineNumber: check.end_location.row,
endColumn: check.end_location.column + 1,
message: `${check.code}: ${check.message}`,
severity: MarkerSeverity.Error,
}))
);
const codeActionProvider = monaco?.languages.registerCodeActionProvider(
"python",
{
// @ts-expect-error: The type definition is wrong.
provideCodeActions: function (model, position) {
const actions = checks
.filter((check) => position.startLineNumber === check.location.row)
.filter((check) => check.fix)
.map((check) => ({
title: `Fix ${check.code}`,
id: `fix-${check.code}`,
kind: "quickfix",
edit: check.fix
? {
edits: [
{
resource: model.uri,
versionId: model.getVersionId(),
edit: {
range: {
startLineNumber: check.fix.location.row,
startColumn: check.fix.location.column + 1,
endLineNumber: check.fix.end_location.row,
endColumn: check.fix.end_location.column + 1,
},
text: check.fix.content,
},
},
],
}
: undefined,
}));
return { actions, dispose: () => {} };
},
}
);
return () => {
codeActionProvider?.dispose();
};
}, [config, source, monaco, initialized]);
const handleEditorChange = useCallback(
(value: string | undefined) => {
setSource(value || "");
},
[setSource]
);
const handleOptionChange = useCallback(
(groupName: string, fieldName: string, value: string) => {
const group = Object.assign({}, (config || {})[groupName]);
if (value === defaultConfig[groupName][fieldName] || value === "") {
delete group[fieldName];
} else {
group[fieldName] = value;
}
setConfig({
...config,
[groupName]: group,
});
},
[config]
);
return (
<div id="app">
<Options
config={config}
defaultConfig={defaultConfig}
onChange={handleOptionChange}
/>
<Editor
options={{ readOnly: false, minimap: { enabled: false } }}
wrapperProps={{ className: "editor" }}
defaultLanguage="python"
value={source || ""}
theme={"light"}
onChange={handleEditorChange}
/>
{error && <div id="error">{error}</div>}
</div>
);
}

View File

@@ -0,0 +1,72 @@
import { Config } from "./config";
import { AVAILABLE_OPTIONS } from "./ruff_options";
function OptionEntry({
config,
defaultConfig,
groupName,
fieldName,
onChange,
}: {
config: Config | null;
defaultConfig: Config;
groupName: string;
fieldName: string;
onChange: (groupName: string, fieldName: string, value: string) => void;
}) {
const value =
config && config[groupName] && config[groupName][fieldName]
? config[groupName][fieldName]
: "";
return (
<span>
<label>
{fieldName}
<input
value={value}
placeholder={defaultConfig[groupName][fieldName]}
type="text"
onChange={(event) => {
onChange(groupName, fieldName, event.target.value);
}}
/>
</label>
</span>
);
}
export function Options({
config,
defaultConfig,
onChange,
}: {
config: Config | null;
defaultConfig: Config;
onChange: (groupName: string, fieldName: string, value: string) => void;
}) {
return (
<div className="options">
{AVAILABLE_OPTIONS.map((group) => (
<details key={group.name}>
<summary>{group.name}</summary>
<div>
<ul>
{group.fields.map((field) => (
<li key={field.name}>
<OptionEntry
config={config}
defaultConfig={defaultConfig}
groupName={group.name}
fieldName={field.name}
onChange={onChange}
/>
</li>
))}
</ul>
</div>
</details>
))}
</div>
);
}

52
playground/src/config.ts Normal file
View File

@@ -0,0 +1,52 @@
import { OptionGroup } from "./ruff_options";
export type Config = { [key: string]: { [key: string]: string } };
export function getDefaultConfig(availableOptions: OptionGroup[]): Config {
const config: Config = {};
availableOptions.forEach((group) => {
config[group.name] = {};
group.fields.forEach((f) => {
config[group.name][f.name] = f.default;
});
});
return config;
}
/**
* Convert the config in the application to something Ruff accepts.
*
* Application config is always nested one level. Ruff allows for some
* top-level options.
*
* Any option value is parsed as JSON to convert it to a native JS object.
* If that fails, e.g. while a user is typing, we let the application handle that
* and show an error.
*/
export function toRuffConfig(config: Config): any {
const convertValue = (value: string): any => {
return value === "None" ? null : JSON.parse(value);
};
const result: any = {};
Object.keys(config).forEach((group_name) => {
const fields = config[group_name];
if (!fields || Object.keys(fields).length === 0) {
return;
}
if (group_name === "globals") {
Object.keys(fields).forEach((field_name) => {
result[field_name] = convertValue(fields[field_name]);
});
} else {
result[group_name] = {};
Object.keys(fields).forEach((field_name) => {
result[group_name][field_name] = convertValue(fields[field_name]);
});
}
});
return result;
}

6
playground/src/custom.d.ts vendored Normal file
View File

@@ -0,0 +1,6 @@
declare module "lz-string" {
function decompressFromEncodedURIComponent(
input: string | null
): string | null;
function compressToEncodedURIComponent(input: string | null): string;
}

10
playground/src/main.tsx Normal file
View File

@@ -0,0 +1,10 @@
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";
import "./style.css";
ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
<React.StrictMode>
<App />
</React.StrictMode>
);

View File

@@ -0,0 +1,239 @@
// This file is auto-generated by `cargo dev generate-playground-options`.
export interface OptionGroup {
name: string;
fields: {
name: string;
default: string;
type: string;
}[];
};
export const AVAILABLE_OPTIONS: OptionGroup[] = [
{"name": "globals", "fields": [
{
"name": "allowed-confusables",
"default": '[]',
"type": 'Vec<char>',
},
{
"name": "dummy-variable-rgx",
"default": '"^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$"',
"type": 'Regex',
},
{
"name": "extend-ignore",
"default": '[]',
"type": 'Vec<CheckCodePrefix>',
},
{
"name": "extend-select",
"default": '[]',
"type": 'Vec<CheckCodePrefix>',
},
{
"name": "external",
"default": '[]',
"type": 'Vec<String>',
},
{
"name": "fix-only",
"default": 'false',
"type": 'bool',
},
{
"name": "ignore",
"default": '[]',
"type": 'Vec<CheckCodePrefix>',
},
{
"name": "line-length",
"default": '88',
"type": 'usize',
},
{
"name": "required-version",
"default": 'None',
"type": 'String',
},
{
"name": "select",
"default": '["E", "F"]',
"type": 'Vec<CheckCodePrefix>',
},
{
"name": "target-version",
"default": '"py310"',
"type": 'PythonVersion',
},
{
"name": "unfixable",
"default": '[]',
"type": 'Vec<CheckCodePrefix>',
},
]},
{"name": "flake8-annotations", "fields": [
{
"name": "allow-star-arg-any",
"default": 'false',
"type": 'bool',
},
{
"name": "mypy-init-return",
"default": 'false',
"type": 'bool',
},
{
"name": "suppress-dummy-args",
"default": 'false',
"type": 'bool',
},
{
"name": "suppress-none-returning",
"default": 'false',
"type": 'bool',
},
]},
{"name": "flake8-bugbear", "fields": [
{
"name": "extend-immutable-calls",
"default": '[]',
"type": 'Vec<String>',
},
]},
{"name": "flake8-errmsg", "fields": [
{
"name": "max-string-length",
"default": '0',
"type": 'usize',
},
]},
{"name": "flake8-import-conventions", "fields": [
{
"name": "aliases",
"default": '{"altair": "alt", "matplotlib.pyplot": "plt", "numpy": "np", "pandas": "pd", "seaborn": "sns"}',
"type": 'FxHashMap<String, String>',
},
{
"name": "extend-aliases",
"default": '{}',
"type": 'FxHashMap<String, String>',
},
]},
{"name": "flake8-quotes", "fields": [
{
"name": "avoid-escape",
"default": 'true',
"type": 'bool',
},
{
"name": "docstring-quotes",
"default": '"double"',
"type": 'Quote',
},
{
"name": "inline-quotes",
"default": '"double"',
"type": 'Quote',
},
{
"name": "multiline-quotes",
"default": '"double"',
"type": 'Quote',
},
]},
{"name": "flake8-tidy-imports", "fields": [
{
"name": "ban-relative-imports",
"default": '"parents"',
"type": 'Strictness',
},
]},
{"name": "flake8-unused-arguments", "fields": [
{
"name": "ignore-variadic-names",
"default": 'false',
"type": 'bool',
},
]},
{"name": "isort", "fields": [
{
"name": "combine-as-imports",
"default": 'false',
"type": 'bool',
},
{
"name": "extra-standard-library",
"default": '[]',
"type": 'Vec<String>',
},
{
"name": "force-single-line",
"default": 'false',
"type": 'bool',
},
{
"name": "force-wrap-aliases",
"default": 'false',
"type": 'bool',
},
{
"name": "known-first-party",
"default": '[]',
"type": 'Vec<String>',
},
{
"name": "known-third-party",
"default": '[]',
"type": 'Vec<String>',
},
{
"name": "single-line-exclusions",
"default": '[]',
"type": 'Vec<String>',
},
{
"name": "split-on-trailing-comma",
"default": 'true',
"type": 'bool',
},
]},
{"name": "mccabe", "fields": [
{
"name": "max-complexity",
"default": '10',
"type": 'usize',
},
]},
{"name": "pep8-naming", "fields": [
{
"name": "classmethod-decorators",
"default": '["classmethod"]',
"type": 'Vec<String>',
},
{
"name": "ignore-names",
"default": '["setUp", "tearDown", "setUpClass", "tearDownClass", "setUpModule", "tearDownModule", "asyncSetUp", "asyncTearDown", "setUpTestData", "failureException", "longMessage", "maxDiff"]',
"type": 'Vec<String>',
},
{
"name": "staticmethod-decorators",
"default": '["staticmethod"]',
"type": 'Vec<String>',
},
]},
{"name": "pydocstyle", "fields": [
{
"name": "convention",
"default": '"convention"',
"type": 'Convention',
},
]},
{"name": "pyupgrade", "fields": [
{
"name": "keep-runtime-typing",
"default": 'false',
"type": 'bool',
},
]},
];

60
playground/src/style.css Normal file
View File

@@ -0,0 +1,60 @@
* {
box-sizing: border-box;
}
body,
html,
#root,
#app {
margin: 0;
height: 100%;
width: 100%;
}
#app {
display: flex;
}
.options {
height: 100vh;
overflow-y: scroll;
padding: 1em;
min-width: 300px;
border-right: 1px solid lightgray;
}
.options ul {
padding-left: 1em;
list-style-type: none;
}
.options li {
margin-bottom: 0.3em;
}
.options details {
margin-bottom: 1em;
}
.options summary {
font-size: 1.3rem;
}
.options input {
display: block;
width: 100%;
}
.editor {
padding: 1em;
}
#error {
position: fixed;
bottom: 0;
width: 100%;
min-height: 1em;
padding: 1em;
background: darkred;
color: white;
}

1
playground/src/vite-env.d.ts vendored Normal file
View File

@@ -0,0 +1 @@
/// <reference types="vite/client" />

21
playground/tsconfig.json Normal file
View File

@@ -0,0 +1,21 @@
{
"compilerOptions": {
"target": "ESNext",
"useDefineForClassFields": true,
"lib": ["DOM", "DOM.Iterable", "ESNext"],
"allowJs": false,
"skipLibCheck": true,
"esModuleInterop": false,
"allowSyntheticDefaultImports": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"module": "ESNext",
"moduleResolution": "Node",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx"
},
"include": ["src"],
"references": [{ "path": "./tsconfig.node.json" }]
}

View File

@@ -0,0 +1,9 @@
{
"compilerOptions": {
"composite": true,
"module": "ESNext",
"moduleResolution": "Node",
"allowSyntheticDefaultImports": true
},
"include": ["vite.config.ts"]
}

View File

@@ -0,0 +1,7 @@
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react-swc";
// https://vitejs.dev/config/
export default defineConfig({
plugins: [react()],
});

View File

@@ -12,6 +12,7 @@ classifiers = [
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3 :: Only",
"Topic :: Software Development :: Libraries :: Python Modules",
"Topic :: Software Development :: Quality Assurance",
@@ -37,3 +38,8 @@ strip = true
[tool.ruff.isort]
force-wrap-aliases = true
combine-as-imports = true
force-single-line = true
single-line-exclusions = ["os", "logging.handlers"]
[tool.ruff.pydocstyle]
convention = "google"

View File

@@ -55,3 +55,5 @@ a.get("hello", False)
{}.pop(True, False)
dict.fromkeys(("world",), True)
{}.deploy(True, False)
getattr(someobj, attrname, False)
mylist.index(True)

View File

@@ -6,6 +6,9 @@ datetime.datetime(2000, 1, 1, 0, 0, 0)
# none args
datetime.datetime(2000, 1, 1, 0, 0, 0, 0, None)
# not none arg
datetime.datetime(2000, 1, 1, 0, 0, 0, 0, datetime.timezone.utc)
# no kwargs
datetime.datetime(2000, 1, 1, fold=1)

View File

@@ -237,3 +237,15 @@ def close(self):
any_failed = True
report(traceback.format_exc())
return any_failed
def global_assignment():
global X
X = 1
return X
def nonlocal_assignment():
X = 1
def inner():
nonlocal X
X = 1
return X

View File

@@ -1,4 +1,5 @@
from abc import abstractmethod
from typing import overload
from typing_extensions import override
@@ -135,3 +136,20 @@ class C:
@override
def f(x):
print("Hello, world!")
###
# Unused arguments attached to overloads (OK).
###
@overload
def f(a: str, b: str) -> str:
...
@overload
def f(a: int, b: int) -> str:
...
def f(a, b):
return f"{a}{b}"

View File

@@ -23,3 +23,6 @@ from A import (
b, # Comment 10
c, # Comment 11
)
from D import a_long_name_to_force_multiple_lines # Comment 12
from D import another_long_name_to_force_multiple_lines # Comment 13

View File

@@ -0,0 +1,18 @@
import sys, math
from os import path, uname
from logging.handlers import StreamHandler, FileHandler
# comment 1
from third_party import lib1, lib2, \
lib3, lib7, lib5, lib6
# comment 2
from third_party import lib4
from foo import bar # comment 3
from foo2 import bar2 # comment 4
# comment 5
from bar import (
a, # comment 6
b, # comment 7
)

View File

@@ -0,0 +1,38 @@
# This has a magic trailing comma, will be sorted, but not rolled into one line
from sys import (
stderr,
argv,
stdout,
exit,
)
# No magic comma, this will be rolled into one line.
from os import (
path,
environ,
execl,
execv
)
from glob import (
glob,
iglob,
escape, # Ends with a comment, should still treat as magic trailing comma.
)
# These will be combined, but without a trailing comma.
from foo import bar
from foo import baz
# These will be combined, _with_ a trailing comma.
from module1 import member1
from module1 import (
member2,
member3,
)
# These will be combined, _with_ a trailing comma.
from module2 import member1, member2
from module2 import (
member3,
)

View File

@@ -0,0 +1,16 @@
import numpy1
import numpy10
import numpy2
from numpy import (
cos,
int8,
sin,
int32,
int64,
tan,
uint8,
uint16,
int16,
uint32,
uint64,
)

View File

@@ -0,0 +1,61 @@
#: E401
import os, sys
#: Okay
import os
import sys
from subprocess import Popen, PIPE
from myclass import MyClass
from foo.bar.yourclass import YourClass
import myclass
import foo.bar.yourclass
#: Okay
__all__ = ['abc']
import foo
#: Okay
__version__ = "42"
import foo
#: Okay
__author__ = "Simon Gomizelj"
import foo
#: Okay
try:
import foo
except ImportError:
pass
else:
print('imported foo')
finally:
print('made attempt to import foo')
import bar
#: Okay
with warnings.catch_warnings():
warnings.filterwarnings("ignore", DeprecationWarning)
import foo
import bar
#: Okay
if False:
import foo
elif not True:
import bar
else:
import mwahaha
import bar
#: E402
VERSION = '1.2.3'
import foo
#: E402
import foo
a = 1
import bar

View File

@@ -15,7 +15,7 @@ import types
if type(res) is not types.ListType:
pass
#: E721
assert type(res) == type(False) or type(res) == type(None)
assert type(res) == type(False)
#: E721
assert type(res) == type([])
#: E721
@@ -52,3 +52,5 @@ if isinstance(res, types.MethodType):
pass
if type(a) != type(b) or type(a) == type(ccc):
pass
assert type(res) == type(None)

View File

@@ -1,2 +1,2 @@
def fn() -> None:
pass
print("Newline present (no W292)")

View File

View File

@@ -0,0 +1 @@

View File

@@ -0,0 +1,84 @@
def f(x, y, z):
"""Do f.
Args:
x: the value
with a hanging indent
Returns:
the value
"""
return x
def f(x, y, z):
"""Do f.
Args:
x:
The whole thing has a hanging indent.
Returns:
the value
"""
return x
def f(x, y, z):
"""Do f.
Args:
x:
The whole thing has a hanging indent.
Returns: the value
"""
return x
def f(x, y, z):
"""Do f.
Args:
x: the value def
ghi
Returns:
the value
"""
return x
def f(x, y, z):
"""Do f.
Args:
x: the value
z: A final argument
Returns:
the value
"""
return x
def f(x, y, z):
"""Do g.
Args:
x: the value
z: A final argument
Returns: the value
"""
return x
def f(x, y, z):
"""Do h.
Args:
x: the value
z: A final argument
"""
return x

View File

@@ -0,0 +1,11 @@
import datetime
import datetime as dt
from datetime import timezone
from datetime import timezone as tz
print(datetime.timezone(-1))
print(timezone.utc)
print(tz.utc)
print(datetime.timezone.utc)
print(dt.timezone.utc)

View File

@@ -0,0 +1,25 @@
# These remain unchanged
str(1)
str(*a)
str("foo", *a)
str(**k)
str("foo", **k)
str("foo", encoding="UTF-8")
str("foo"
"bar")
bytes("foo", encoding="UTF-8")
bytes(*a)
bytes("foo", *a)
bytes("foo", **a)
bytes(b"foo"
b"bar")
# These become string or byte literals
str()
str("foo")
str("""
foo""")
bytes()
bytes(b"foo")
bytes(b"""
foo""")

View File

@@ -0,0 +1,20 @@
import typing
import typing as Hello
from typing import Text
from typing import Text as Goodbye
def print_word(word: Text) -> None:
print(word)
def print_second_word(word: typing.Text) -> None:
print(word)
def print_third_word(word: Hello.Text) -> None:
print(word)
def print_fourth_word(word: Goodbye) -> None:
print(word)

View File

@@ -0,0 +1,9 @@
from io import open
with open("f.txt") as f:
print(f.read())
import io
with io.open("f.txt", mode="r", buffering=-1, **kwargs) as f:
print(f.read())

View File

@@ -0,0 +1,12 @@
import subprocess
import subprocess as somename
from subprocess import run
from subprocess import run as anothername
subprocess.run(["foo"], universal_newlines=True, check=True)
somename.run(["foo"], universal_newlines=True)
run(["foo"], universal_newlines=True, check=False)
anothername(["foo"], universal_newlines=True)
subprocess.run(["foo"], check=True)

View File

@@ -0,0 +1,42 @@
from subprocess import run
import subprocess
output = run(["foo"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
output = subprocess.run(["foo"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
output = subprocess.run(stdout=subprocess.PIPE, args=["foo"], stderr=subprocess.PIPE)
output = subprocess.run(
["foo"], stdout=subprocess.PIPE, check=True, stderr=subprocess.PIPE
)
output = subprocess.run(
["foo"], stderr=subprocess.PIPE, check=True, stdout=subprocess.PIPE
)
output = subprocess.run(
["foo"],
stdout=subprocess.PIPE,
check=True,
stderr=subprocess.PIPE,
text=True,
encoding="utf-8",
close_fds=True,
)
if output:
output = subprocess.run(
["foo"],
stdout=subprocess.PIPE,
check=True,
stderr=subprocess.PIPE,
text=True,
encoding="utf-8",
)
# Examples that should NOT trigger the rule
from foo import PIPE
subprocess.run(["foo"], stdout=PIPE, stderr=PIPE)
run(["foo"], stdout=None, stderr=PIPE)

View File

@@ -0,0 +1,31 @@
# These two imports have something after cElementTree, so they should be fixed.
from xml.etree.cElementTree import XML, Element, SubElement
import xml.etree.cElementTree as ET
# Weird spacing should not cause issues.
from xml.etree.cElementTree import XML
import xml.etree.cElementTree as ET
# Multi line imports should also work fine.
from xml.etree.cElementTree import (
XML,
Element,
SubElement,
)
if True:
import xml.etree.cElementTree as ET
from xml.etree import cElementTree as CET
from xml.etree import cElementTree as ET
import contextlib, xml.etree.cElementTree as ET
# This should fix the second, but not the first invocation.
import xml.etree.cElementTree, xml.etree.cElementTree as ET
# The below items should NOT be changed.
import xml.etree.cElementTree
from .xml.etree.cElementTree import XML
from xml.etree import cElementTree

15
resources/test/fixtures/ruff/RUF004.py vendored Normal file
View File

@@ -0,0 +1,15 @@
def f(*args, **kwargs):
pass
a = (1, 2)
b = (3, 4)
c = (5, 6)
d = (7, 8)
f(a, b)
f(a, kw=b)
f(*a, kw=b)
f(kw=a, *b)
f(kw=a, *b, *c)
f(*a, kw=b, *c, kw1=d)

View File

@@ -15,8 +15,8 @@ def f() -> None:
# Invalid
d = 1 # noqa: F841, E501
# Invalid (and unimplemented)
d = 1 # noqa: F841, W191
# Invalid (and unimplemented or not enabled)
d = 1 # noqa: F841, W191, F821
# Invalid (but external)
d = 1 # noqa: F841, V101

View File

@@ -9,14 +9,14 @@ Running from the repo root should pick up and enforce the appropriate settings f
```
∴ cargo run resources/test/project/
Found 7 error(s).
resources/test/project/examples/.dotfiles/script.py:1:1: I001 Import block is un-sorted or un-formatted
resources/test/project/examples/.dotfiles/script.py:1:8: F401 `numpy` imported but unused
resources/test/project/examples/.dotfiles/script.py:2:17: F401 `app.app_file` imported but unused
resources/test/project/examples/docs/docs/file.py:1:1: I001 Import block is un-sorted or un-formatted
resources/test/project/examples/docs/docs/file.py:8:5: F841 Local variable `x` is assigned to but never used
resources/test/project/src/file.py:1:8: F401 `os` imported but unused
resources/test/project/src/import_file.py:1:1: I001 Import block is un-sorted or un-formatted
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).
6 potentially fixable with the --fix option.
```
@@ -24,14 +24,14 @@ Running from the project directory itself should exhibit the same behavior:
```
∴ (cd resources/test/project/ && cargo run .)
Found 7 error(s).
examples/.dotfiles/script.py:1:1: I001 Import block is un-sorted or un-formatted
examples/.dotfiles/script.py:1:8: F401 `numpy` imported but unused
examples/.dotfiles/script.py:2:17: F401 `app.app_file` imported but unused
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
src/file.py:1:8: F401 `os` imported but unused
src/import_file.py:1:1: I001 Import block is un-sorted or un-formatted
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).
6 potentially fixable with the --fix option.
```
@@ -40,9 +40,9 @@ files:
```
∴ (cd resources/test/project/examples/docs && cargo run .)
Found 2 error(s).
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).
1 potentially fixable with the --fix option.
```
@@ -51,8 +51,6 @@ file paths from the current working directory:
```
∴ (cargo run -- --config=resources/test/project/pyproject.toml resources/test/project/)
Found 11 error(s).
resources/test/project/examples/.dotfiles/script.py:1:1: I001 Import block is un-sorted or un-formatted
resources/test/project/examples/.dotfiles/script.py:1:8: F401 `numpy` imported but unused
resources/test/project/examples/.dotfiles/script.py:2:17: F401 `app.app_file` imported but unused
resources/test/project/examples/docs/docs/concepts/file.py:1:8: F401 `os` imported but unused
@@ -61,9 +59,9 @@ resources/test/project/examples/docs/docs/file.py:1:8: F401 `os` imported but un
resources/test/project/examples/docs/docs/file.py:3:8: F401 `numpy` imported but unused
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/src/file.py:1:8: F401 `os` imported but unused
resources/test/project/src/import_file.py:1:1: I001 Import block is un-sorted or un-formatted
11 potentially fixable with the --fix option.
resources/test/project/project/file.py:1:8: F401 `os` imported but unused
Found 9 error(s).
9 potentially fixable with the --fix option.
```
Running from a parent directory should this "ignore" the `exclude` (hence, `concepts/file.py` gets
@@ -71,11 +69,11 @@ included in the output):
```
∴ (cd resources/test/project/examples && cargo run -- --config=docs/pyproject.toml .)
Found 4 error(s).
docs/docs/concepts/file.py:5:5: F841 Local variable `x` is assigned to but never used
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).
1 potentially fixable with the --fix option.
```
@@ -83,7 +81,14 @@ Passing an excluded directory directly should report errors in the contained fil
```
∴ cargo run resources/test/project/examples/excluded/
Found 1 error(s).
resources/test/project/examples/excluded/script.py:1:8: F401 `os` imported but unused
Found 1 error(s).
1 potentially fixable with the --fix option.
```
Unless we `--force-exclude`:
```
∴ cargo run resources/test/project/examples/excluded/ --force-exclude
∴ cargo run resources/test/project/examples/excluded/script.py --force-exclude
```

View File

@@ -1,4 +1,3 @@
[tool.ruff]
extend = "../../pyproject.toml"
src = ["."]
# Enable I001, and re-enable F841, to test extension priority.

1284
ruff.schema.json Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
[package]
name = "ruff_dev"
version = "0.0.190"
version = "0.0.199"
edition = "2021"
[dependencies]
@@ -11,8 +11,11 @@ itertools = { version = "0.10.5" }
libcst = { git = "https://github.com/charliermarsh/LibCST", rev = "f2f0b7a487a8725d161fe8b3ed73a6758b21e177" }
once_cell = { version = "1.16.0" }
ruff = { path = ".." }
rustpython-ast = { features = ["unparse"], git = "https://github.com/RustPython/RustPython.git", rev = "c01f014b1269eedcf4bdb45d5fbc62ae2beecf31" }
rustpython-common = { git = "https://github.com/RustPython/RustPython.git", rev = "c01f014b1269eedcf4bdb45d5fbc62ae2beecf31" }
rustpython-parser = { features = ["lalrpop"], git = "https://github.com/RustPython/RustPython.git", rev = "c01f014b1269eedcf4bdb45d5fbc62ae2beecf31" }
rustpython-ast = { features = ["unparse"], git = "https://github.com/RustPython/RustPython.git", rev = "68d26955b3e24198a150315e7959719b03709dee" }
rustpython-common = { git = "https://github.com/RustPython/RustPython.git", rev = "68d26955b3e24198a150315e7959719b03709dee" }
rustpython-parser = { features = ["lalrpop"], git = "https://github.com/RustPython/RustPython.git", rev = "68d26955b3e24198a150315e7959719b03709dee" }
schemars = { version = "0.8.11" }
serde_json = {version="1.0.91"}
strum = { version = "0.24.1", features = ["strum_macros"] }
strum_macros = { version = "0.24.3" }
textwrap = { version = "0.16.0" }

View File

@@ -0,0 +1,35 @@
//! Run all code and documentation generation steps.
use anyhow::Result;
use clap::Args;
use crate::{
generate_check_code_prefix, generate_json_schema, generate_options,
generate_playground_options, generate_rules_table,
};
#[derive(Args)]
pub struct Cli {
/// Write the generated artifacts to stdout (rather than to the filesystem).
#[arg(long)]
dry_run: bool,
}
pub fn main(cli: &Cli) -> Result<()> {
generate_check_code_prefix::main(&generate_check_code_prefix::Cli {
dry_run: cli.dry_run,
})?;
generate_json_schema::main(&generate_json_schema::Cli {
dry_run: cli.dry_run,
})?;
generate_rules_table::main(&generate_rules_table::Cli {
dry_run: cli.dry_run,
})?;
generate_options::main(&generate_options::Cli {
dry_run: cli.dry_run,
})?;
generate_playground_options::main(&generate_playground_options::Cli {
dry_run: cli.dry_run,
})?;
Ok(())
}

View File

@@ -10,16 +10,18 @@ use anyhow::{ensure, Result};
use clap::Parser;
use codegen::{Scope, Type, Variant};
use itertools::Itertools;
use ruff::checks::{CheckCode, CODE_REDIRECTS, PREFIX_REDIRECTS};
use ruff::checks::{CheckCode, PREFIX_REDIRECTS};
use strum::IntoEnumIterator;
const ALL: &str = "ALL";
#[derive(Parser)]
#[command(author, version, about, long_about = None)]
pub struct Cli {
/// Write the generated source code to stdout (rather than to
/// `src/checks_gen.rs`).
#[arg(long)]
dry_run: bool,
pub(crate) dry_run: bool,
}
pub fn main(cli: &Cli) -> Result<()> {
@@ -34,24 +36,19 @@ pub fn main(cli: &Cli) -> Result<()> {
let code_suffix_len = code_str.len() - code_prefix_len;
for i in 0..=code_suffix_len {
let prefix = code_str[..code_prefix_len + i].to_string();
let entry = prefix_to_codes.entry(prefix).or_default();
entry.insert(check_code.clone());
prefix_to_codes
.entry(prefix)
.or_default()
.insert(check_code.clone());
}
prefix_to_codes
.entry(ALL.to_string())
.or_default()
.insert(check_code.clone());
}
// Add any prefix aliases (e.g., "U" to "UP").
for (alias, source) in PREFIX_REDIRECTS.iter() {
prefix_to_codes.insert(
(*alias).to_string(),
prefix_to_codes
.get(&(*source).to_string())
.unwrap_or_else(|| panic!("Unknown CheckCode: {source:?}"))
.clone(),
);
}
// Add any check code aliases (e.g., "U001" to "UP001").
for (alias, check_code) in CODE_REDIRECTS.iter() {
for (alias, check_code) in PREFIX_REDIRECTS.iter() {
prefix_to_codes.insert(
(*alias).to_string(),
prefix_to_codes
@@ -76,7 +73,8 @@ pub fn main(cli: &Cli) -> Result<()> {
.derive("Ord")
.derive("Clone")
.derive("Serialize")
.derive("Deserialize");
.derive("Deserialize")
.derive("JsonSchema");
for prefix in prefix_to_codes.keys() {
gen = gen.push_variant(Variant::new(prefix.to_string()));
}
@@ -89,6 +87,7 @@ pub fn main(cli: &Cli) -> Result<()> {
.derive("Eq")
.derive("PartialOrd")
.derive("Ord")
.push_variant(Variant::new("None"))
.push_variant(Variant::new("Zero"))
.push_variant(Variant::new("One"))
.push_variant(Variant::new("Two"))
@@ -105,7 +104,7 @@ pub fn main(cli: &Cli) -> Result<()> {
.line("#[allow(clippy::match_same_arms)]")
.line("match self {");
for (prefix, codes) in &prefix_to_codes {
if let Some(target) = CODE_REDIRECTS.get(&prefix.as_str()) {
if let Some(target) = PREFIX_REDIRECTS.get(&prefix.as_str()) {
gen = gen.line(format!(
"CheckCodePrefix::{prefix} => {{ one_time_warning!(\"{{}}{{}} {{}}\", \
\"warning\".yellow().bold(), \":\".bold(), \"`{}` has been remapped to \
@@ -117,18 +116,6 @@ pub fn main(cli: &Cli) -> Result<()> {
.map(|code| format!("CheckCode::{}", code.as_ref()))
.join(", ")
));
} else if let Some(target) = PREFIX_REDIRECTS.get(&prefix.as_str()) {
gen = gen.line(format!(
"CheckCodePrefix::{prefix} => {{ one_time_warning!(\"{{}}{{}} {{}}\", \
\"warning\".yellow().bold(), \":\".bold(), \"`{}` has been remapped to \
`{}`\".bold()); \n vec![{}] }}",
prefix,
target,
codes
.iter()
.map(|code| format!("CheckCode::{}", code.as_ref()))
.join(", ")
));
} else {
gen = gen.line(format!(
"CheckCodePrefix::{prefix} => vec![{}],",
@@ -151,18 +138,21 @@ pub fn main(cli: &Cli) -> Result<()> {
.line("#[allow(clippy::match_same_arms)]")
.line("match self {");
for prefix in prefix_to_codes.keys() {
let num_numeric = prefix.chars().filter(|char| char.is_numeric()).count();
let specificity = match num_numeric {
0 => "Zero",
1 => "One",
2 => "Two",
3 => "Three",
4 => "Four",
_ => panic!("Invalid prefix: {prefix}"),
let specificity = if prefix == "ALL" {
"None"
} else {
let num_numeric = prefix.chars().filter(|char| char.is_numeric()).count();
match num_numeric {
0 => "Zero",
1 => "One",
2 => "Two",
3 => "Three",
4 => "Four",
_ => panic!("Invalid prefix: {prefix}"),
}
};
gen = gen.line(format!(
"CheckCodePrefix::{prefix} => SuffixLength::{},",
specificity
"CheckCodePrefix::{prefix} => SuffixLength::{specificity},"
));
}
gen.line("}");
@@ -175,6 +165,8 @@ pub fn main(cli: &Cli) -> Result<()> {
output.push('\n');
output.push_str("use colored::Colorize;");
output.push('\n');
output.push_str("use schemars::JsonSchema;");
output.push('\n');
output.push_str("use serde::{Deserialize, Serialize};");
output.push('\n');
output.push_str("use strum_macros::{AsRefStr, EnumString};");

View File

@@ -0,0 +1,30 @@
use std::fs;
use std::path::PathBuf;
use anyhow::Result;
use clap::Args;
use ruff::settings::options::Options;
use schemars::schema_for;
#[derive(Args)]
pub struct Cli {
/// Write the generated table to stdout (rather than to `ruff.schema.json`).
#[arg(long)]
pub(crate) dry_run: bool,
}
pub fn main(cli: &Cli) -> Result<()> {
let schema = schema_for!(Options);
let schema_string = serde_json::to_string_pretty(&schema).unwrap();
if cli.dry_run {
println!("{schema_string}");
} else {
let file = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.parent()
.expect("Failed to find root directory")
.join("ruff.schema.json");
fs::write(file, schema_string.as_bytes())?;
}
Ok(())
}

View File

@@ -18,7 +18,7 @@ const END_PRAGMA: &str = "<!-- End auto-generated options sections. -->";
pub struct Cli {
/// Write the generated table to stdout (rather than to `README.md`).
#[arg(long)]
dry_run: bool,
pub(crate) dry_run: bool,
}
fn emit_field(output: &mut String, field: &OptionField, group_name: Option<&str>) {

View File

@@ -0,0 +1,142 @@
//! Generate typescript file defining options to be used by the web playground.
use std::fs::OpenOptions;
use std::io::Write;
use std::path::PathBuf;
use anyhow::Result;
use clap::Args;
use itertools::Itertools;
use ruff::settings::options::Options;
use ruff::settings::options_base::{ConfigurationOptions, OptionEntry, OptionField};
#[derive(Args)]
pub struct Cli {
/// Write the generated table to stdout (rather than to `TODO`).
#[arg(long)]
pub(crate) dry_run: bool,
}
fn emit_field(output: &mut String, field: &OptionField) {
output.push_str(&textwrap::indent(
&textwrap::dedent(&format!(
"
{{
\"name\": \"{}\",
\"default\": '{}',
\"type\": '{}',
}},",
field.name, field.default, field.value_type
)),
" ",
));
}
pub fn main(cli: &Cli) -> Result<()> {
let mut output = String::new();
// Generate all the top-level fields.
output.push_str(&format!("{{\"name\": \"{}\", \"fields\": [", "globals"));
for field in Options::get_available_options()
.into_iter()
.filter_map(|entry| {
if let OptionEntry::Field(field) = entry {
Some(field)
} else {
None
}
})
// Filter out options that don't make sense in the playground.
.filter(|field| {
!matches!(
field.name,
"src"
| "fix"
| "format"
| "exclude"
| "extend"
| "extend-exclude"
| "fixable"
| "force-exclude"
| "ignore-init-module-imports"
| "respect-gitignore"
| "show-source"
| "cache-dir"
| "per-file-ignores"
)
})
.sorted_by_key(|field| field.name)
{
emit_field(&mut output, &field);
}
output.push_str("\n]},\n");
// Generate all the sub-groups.
for group in Options::get_available_options()
.into_iter()
.filter_map(|entry| {
if let OptionEntry::Group(group) = entry {
Some(group)
} else {
None
}
})
.sorted_by_key(|group| group.name)
{
output.push_str(&format!("{{\"name\": \"{}\", \"fields\": [", group.name));
for field in group
.fields
.iter()
.filter_map(|entry| {
if let OptionEntry::Field(field) = entry {
Some(field)
} else {
None
}
})
.sorted_by_key(|field| field.name)
{
emit_field(&mut output, field);
}
output.push_str("\n]},\n");
}
let prefix = textwrap::dedent(
r"
// This file is auto-generated by `cargo dev generate-playground-options`.
export interface OptionGroup {
name: string;
fields: {
name: string;
default: string;
type: string;
}[];
};
export const AVAILABLE_OPTIONS: OptionGroup[] = [
",
);
let postfix = "];";
if cli.dry_run {
print!("{output}");
} else {
let file = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.parent()
.expect("Failed to find root directory")
.join("playground")
.join("src")
.join("ruff_options.ts");
let mut f = OpenOptions::new()
.create(true)
.write(true)
.truncate(true)
.open(file)?;
write!(f, "{prefix}")?;
write!(f, "{}", textwrap::indent(&output, " "))?;
write!(f, "{postfix}")?;
}
Ok(())
}

View File

@@ -21,7 +21,7 @@ const TOC_END_PRAGMA: &str = "<!-- End auto-generated table of contents. -->";
pub struct Cli {
/// Write the generated table to stdout (rather than to `README.md`).
#[arg(long)]
dry_run: bool,
pub(crate) dry_run: bool,
}
pub fn main(cli: &Cli) -> Result<()> {

View File

@@ -11,10 +11,13 @@
clippy::too_many_lines
)]
pub mod generate_all;
pub mod generate_check_code_prefix;
pub mod generate_json_schema;
pub mod generate_options;
pub mod generate_playground_options;
pub mod generate_rules_table;
pub mod generate_source_code;
pub mod print_ast;
pub mod print_cst;
pub mod print_tokens;
pub mod round_trip;

View File

@@ -14,8 +14,9 @@
use anyhow::Result;
use clap::{Parser, Subcommand};
use ruff_dev::{
generate_check_code_prefix, generate_options, generate_rules_table, generate_source_code,
print_ast, print_cst, print_tokens,
generate_all, generate_check_code_prefix, generate_json_schema, generate_options,
generate_playground_options, generate_rules_table, print_ast, print_cst, print_tokens,
round_trip,
};
#[derive(Parser)]
@@ -28,32 +29,42 @@ struct Cli {
#[derive(Subcommand)]
enum Commands {
/// Run all code and documentation generation steps.
GenerateAll(generate_all::Cli),
/// Generate the `CheckCodePrefix` enum.
GenerateCheckCodePrefix(generate_check_code_prefix::Cli),
/// Generate JSON schema for the TOML configuration file.
GenerateJSONSchema(generate_json_schema::Cli),
/// Generate a Markdown-compatible table of supported lint rules.
GenerateRulesTable(generate_rules_table::Cli),
/// Generate a Markdown-compatible listing of configuration options.
GenerateOptions(generate_options::Cli),
/// Run round-trip source code generation on a given Python file.
GenerateSourceCode(generate_source_code::Cli),
/// Generate typescript file defining options to be used by the web
/// playground.
GeneratePlaygroundOptions(generate_playground_options::Cli),
/// Print the AST for a given Python file.
PrintAST(print_ast::Cli),
/// Print the LibCST CST for a given Python file.
PrintCST(print_cst::Cli),
/// Print the token stream for a given Python file.
PrintTokens(print_tokens::Cli),
/// Run round-trip source code generation on a given Python file.
RoundTrip(round_trip::Cli),
}
fn main() -> Result<()> {
let cli = Cli::parse();
match &cli.command {
Commands::GenerateAll(args) => generate_all::main(args)?,
Commands::GenerateCheckCodePrefix(args) => generate_check_code_prefix::main(args)?,
Commands::GenerateJSONSchema(args) => generate_json_schema::main(args)?,
Commands::GenerateRulesTable(args) => generate_rules_table::main(args)?,
Commands::GenerateSourceCode(args) => generate_source_code::main(args)?,
Commands::GenerateOptions(args) => generate_options::main(args)?,
Commands::GeneratePlaygroundOptions(args) => generate_playground_options::main(args)?,
Commands::PrintAST(args) => print_ast::main(args)?,
Commands::PrintCST(args) => print_cst::main(args)?,
Commands::PrintTokens(args) => print_tokens::main(args)?,
Commands::RoundTrip(args) => round_trip::main(args)?,
}
Ok(())
}

View File

@@ -5,7 +5,9 @@ use std::path::PathBuf;
use anyhow::Result;
use clap::Args;
use ruff::code_gen::SourceGenerator;
use ruff::source_code_generator::SourceCodeGenerator;
use ruff::source_code_locator::SourceCodeLocator;
use ruff::source_code_style::SourceCodeStyleDetector;
use rustpython_parser::parser;
#[derive(Args)]
@@ -18,7 +20,9 @@ pub struct Cli {
pub fn main(cli: &Cli) -> Result<()> {
let contents = fs::read_to_string(&cli.file)?;
let python_ast = parser::parse_program(&contents, &cli.file.to_string_lossy())?;
let mut generator = SourceGenerator::new();
let locator = SourceCodeLocator::new(&contents);
let stylist = SourceCodeStyleDetector::from_contents(&contents, &locator);
let mut generator = SourceCodeGenerator::new(stylist.indentation(), stylist.quote());
generator.unparse_suite(&python_ast);
println!("{}", generator.generate()?);
Ok(())

View File

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

View File

@@ -13,13 +13,14 @@
use quote::{quote, quote_spanned};
use syn::parse::{Parse, ParseStream};
use syn::spanned::Spanned;
use syn::token::Comma;
use syn::{
parse_macro_input, AngleBracketedGenericArguments, Attribute, Data, DataStruct, DeriveInput,
Field, Fields, Lit, LitStr, Path, PathArguments, PathSegment, Token, Type, TypePath,
};
#[proc_macro_derive(ConfigurationOptions, attributes(option, option_group))]
#[proc_macro_derive(ConfigurationOptions, attributes(option, doc, option_group))]
pub fn derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let input = parse_macro_input!(input as DeriveInput);
@@ -39,11 +40,28 @@ fn derive_impl(input: DeriveInput) -> syn::Result<proc_macro2::TokenStream> {
let mut output = vec![];
for field in fields.named.iter() {
if let Some(attr) = field.attrs.iter().find(|a| a.path.is_ident("option")) {
output.push(handle_option(field, attr)?);
let docs: Vec<&Attribute> = field
.attrs
.iter()
.filter(|attr| attr.path.is_ident("doc"))
.collect();
if docs.is_empty() {
return Err(syn::Error::new(
field.span(),
"Missing documentation for field",
));
}
if let Some(attr) = field.attrs.iter().find(|attr| attr.path.is_ident("option")) {
output.push(handle_option(field, attr, docs)?);
};
if field.attrs.iter().any(|a| a.path.is_ident("option_group")) {
if field
.attrs
.iter()
.any(|attr| attr.path.is_ident("option_group"))
{
output.push(handle_option_group(field)?);
};
}
@@ -70,8 +88,10 @@ fn derive_impl(input: DeriveInput) -> syn::Result<proc_macro2::TokenStream> {
/// deriving `ConfigurationOptions`, create code that calls retrieves options
/// from that group: `Foobar::get_available_options()`
fn handle_option_group(field: &Field) -> syn::Result<proc_macro2::TokenStream> {
// unwrap is safe because we're only going over named fields
let ident = field.ident.as_ref().unwrap();
let ident = field
.ident
.as_ref()
.expect("Expected to handle named fields");
match &field.ty {
Type::Path(TypePath {
@@ -103,17 +123,49 @@ fn handle_option_group(field: &Field) -> syn::Result<proc_macro2::TokenStream> {
}
}
/// Parse a `doc` attribute into it a string literal.
fn parse_doc(doc: &Attribute) -> syn::Result<String> {
let doc = doc
.parse_meta()
.map_err(|e| syn::Error::new(doc.span(), e))?;
match doc {
syn::Meta::NameValue(syn::MetaNameValue {
lit: Lit::Str(lit_str),
..
}) => Ok(lit_str.value()),
_ => Err(syn::Error::new(doc.span(), "Expected doc attribute.")),
}
}
/// Parse an `#[option(doc="...", default="...", value_type="...",
/// example="...")]` attribute and return data in the form of an `OptionField`.
fn handle_option(field: &Field, attr: &Attribute) -> syn::Result<proc_macro2::TokenStream> {
// unwrap is safe because we're only going over named fields
let ident = field.ident.as_ref().unwrap();
fn handle_option(
field: &Field,
attr: &Attribute,
docs: Vec<&Attribute>,
) -> syn::Result<proc_macro2::TokenStream> {
// Convert the list of `doc` attributes into a single string.
let doc = textwrap::dedent(
&docs
.into_iter()
.map(parse_doc)
.collect::<syn::Result<Vec<_>>>()?
.join("\n"),
)
.trim_matches('\n')
.to_string();
let ident = field
.ident
.as_ref()
.expect("Expected to handle named fields");
let FieldAttributes {
doc,
default,
value_type,
example,
..
} = attr.parse_args::<FieldAttributes>()?;
let kebab_name = LitStr::new(&ident.to_string().replace('_', "-"), ident.span());
@@ -130,7 +182,6 @@ fn handle_option(field: &Field, attr: &Attribute) -> syn::Result<proc_macro2::To
#[derive(Debug)]
struct FieldAttributes {
doc: String,
default: String,
value_type: String,
example: String,
@@ -138,8 +189,6 @@ struct FieldAttributes {
impl Parse for FieldAttributes {
fn parse(input: ParseStream) -> syn::Result<Self> {
let doc = _parse_key_value(input, "doc")?;
input.parse::<Comma>()?;
let default = _parse_key_value(input, "default")?;
input.parse::<Comma>()?;
let value_type = _parse_key_value(input, "value_type")?;
@@ -150,7 +199,6 @@ impl Parse for FieldAttributes {
}
Ok(FieldAttributes {
doc: textwrap::dedent(&doc).trim_matches('\n').to_string(),
default,
value_type,
example: textwrap::dedent(&example).trim_matches('\n').to_string(),

View File

@@ -1,3 +1,4 @@
use itertools::Itertools;
use log::error;
use once_cell::sync::Lazy;
use regex::Regex;
@@ -381,10 +382,8 @@ pub fn identifier_range(stmt: &Stmt, locator: &SourceCodeLocator) -> Range {
| StmtKind::AsyncFunctionDef { .. }
) {
let contents = locator.slice_source_code_range(&Range::from_located(stmt));
for (start, tok, end) in lexer::make_tokenizer(&contents).flatten() {
for (start, tok, end) in lexer::make_tokenizer_located(&contents, stmt.location).flatten() {
if matches!(tok, Tok::Name { .. }) {
let start = to_absolute(start, stmt.location);
let end = to_absolute(end, stmt.location);
return Range {
location: start,
end_location: end,
@@ -396,6 +395,37 @@ pub fn identifier_range(stmt: &Stmt, locator: &SourceCodeLocator) -> Range {
Range::from_located(stmt)
}
/// Return the `Range` of `name` in `Excepthandler`.
pub fn excepthandler_name_range(
handler: &Excepthandler,
locator: &SourceCodeLocator,
) -> Option<Range> {
let ExcepthandlerKind::ExceptHandler {
name, type_, body, ..
} = &handler.node;
match (name, type_) {
(Some(_), Some(type_)) => {
let type_end_location = type_.end_location.unwrap();
let contents = locator.slice_source_code_range(&Range {
location: type_end_location,
end_location: body[0].location,
});
let range = lexer::make_tokenizer_located(&contents, type_end_location)
.flatten()
.tuple_windows()
.find(|(tok, next_tok)| {
matches!(tok.1, Tok::As) && matches!(next_tok.1, Tok::Name { .. })
})
.map(|((..), (location, _, end_location))| Range {
location,
end_location,
});
range
}
_ => None,
}
}
/// Return `true` if a `Stmt` appears to be part of a multi-statement line, with
/// other statements preceding it.
pub fn preceded_by_continuation(stmt: &Stmt, locator: &SourceCodeLocator) -> bool {

View File

@@ -14,6 +14,7 @@ use crate::source_code_locator::SourceCodeLocator;
pub enum Mode {
Generate,
Apply,
Diff,
None,
}

View File

@@ -3,7 +3,7 @@ use std::fs;
use std::fs::{create_dir_all, File, Metadata};
use std::hash::{Hash, Hasher};
use std::io::Write;
use std::path::Path;
use std::path::{Path, PathBuf};
use anyhow::Result;
use filetime::FileTime;
@@ -12,7 +12,6 @@ use once_cell::sync::Lazy;
use path_absolutize::Absolutize;
use serde::{Deserialize, Serialize};
use crate::autofix::fixer;
use crate::message::Message;
use crate::settings::{flags, Settings};
@@ -36,15 +35,19 @@ struct CheckResult {
messages: Vec<Message>,
}
fn cache_dir() -> &'static Path {
Path::new(CACHE_DIR.as_ref().map_or(".ruff_cache", String::as_str))
/// Return the cache directory for a given project root. Defers to the
/// `RUFF_CACHE_DIR` environment variable, if set.
pub fn cache_dir(project_root: &Path) -> PathBuf {
CACHE_DIR
.as_ref()
.map_or_else(|| project_root.join(".ruff_cache"), PathBuf::from)
}
fn content_dir() -> &'static Path {
Path::new("content")
}
fn cache_key<P: AsRef<Path>>(path: P, settings: &Settings, autofix: fixer::Mode) -> u64 {
fn cache_key<P: AsRef<Path>>(path: P, settings: &Settings, autofix: flags::Autofix) -> u64 {
let mut hasher = DefaultHasher::new();
CARGO_PKG_VERSION.hash(&mut hasher);
path.as_ref().absolutize().unwrap().hash(&mut hasher);
@@ -53,10 +56,8 @@ fn cache_key<P: AsRef<Path>>(path: P, settings: &Settings, autofix: fixer::Mode)
hasher.finish()
}
/// Initialize the cache directory.
pub fn init() -> Result<()> {
let path = cache_dir();
/// Initialize the cache at the specified `Path`.
pub fn init(path: &Path) -> Result<()> {
// Create the cache directories.
create_dir_all(path.join(content_dir()))?;
@@ -75,15 +76,15 @@ pub fn init() -> Result<()> {
Ok(())
}
fn write_sync(key: u64, value: &[u8]) -> Result<(), std::io::Error> {
fn write_sync(cache_dir: &Path, key: u64, value: &[u8]) -> Result<(), std::io::Error> {
fs::write(
cache_dir().join(content_dir()).join(format!("{key:x}")),
cache_dir.join(content_dir()).join(format!("{key:x}")),
value,
)
}
fn read_sync(key: u64) -> Result<Vec<u8>, std::io::Error> {
fs::read(cache_dir().join(content_dir()).join(format!("{key:x}")))
fn read_sync(cache_dir: &Path, key: u64) -> Result<Vec<u8>, std::io::Error> {
fs::read(cache_dir.join(content_dir()).join(format!("{key:x}")))
}
/// Get a value from the cache.
@@ -91,14 +92,9 @@ pub fn get<P: AsRef<Path>>(
path: P,
metadata: &Metadata,
settings: &Settings,
autofix: fixer::Mode,
cache: flags::Cache,
autofix: flags::Autofix,
) -> Option<Vec<Message>> {
if matches!(cache, flags::Cache::Disabled) {
return None;
};
let encoded = read_sync(cache_key(path, settings, autofix)).ok()?;
let encoded = read_sync(&settings.cache_dir, cache_key(path, settings, autofix)).ok()?;
let (mtime, messages) = match bincode::deserialize::<CheckResult>(&encoded[..]) {
Ok(CheckResult {
metadata: CacheMetadata { mtime },
@@ -120,14 +116,9 @@ pub fn set<P: AsRef<Path>>(
path: P,
metadata: &Metadata,
settings: &Settings,
autofix: fixer::Mode,
autofix: flags::Autofix,
messages: &[Message],
cache: flags::Cache,
) {
if matches!(cache, flags::Cache::Disabled) {
return;
};
let check_result = CheckResultRef {
metadata: &CacheMetadata {
mtime: FileTime::from_last_modification_time(metadata).unix_seconds(),
@@ -135,6 +126,7 @@ pub fn set<P: AsRef<Path>>(
messages,
};
if let Err(e) = write_sync(
&settings.cache_dir,
cache_key(path, settings, autofix),
&bincode::serialize(&check_result).unwrap(),
) {

View File

@@ -33,14 +33,16 @@ use crate::python::typing::SubscriptKind;
use crate::settings::types::PythonVersion;
use crate::settings::{flags, Settings};
use crate::source_code_locator::SourceCodeLocator;
use crate::vendored::cformat::{CFormatError, CFormatErrorType};
use crate::source_code_style::SourceCodeStyleDetector;
use crate::vendor::cformat::{CFormatError, CFormatErrorType};
use crate::visibility::{module_visibility, transition_scope, Modifier, Visibility, VisibleScope};
use crate::{
docstrings, flake8_2020, flake8_annotations, flake8_bandit, flake8_blind_except,
flake8_boolean_trap, flake8_bugbear, flake8_builtins, flake8_comprehensions, flake8_datetimez,
flake8_debugger, flake8_errmsg, flake8_import_conventions, flake8_print, flake8_return,
flake8_simplify, flake8_tidy_imports, flake8_unused_arguments, mccabe, noqa, pandas_vet,
pep8_naming, pycodestyle, pydocstyle, pyflakes, pygrep_hooks, pylint, pyupgrade, visibility,
pep8_naming, pycodestyle, pydocstyle, pyflakes, pygrep_hooks, pylint, pyupgrade, ruff,
visibility,
};
const GLOBAL_SCOPE_INDEX: usize = 0;
@@ -56,6 +58,7 @@ pub struct Checker<'a> {
pub(crate) settings: &'a Settings,
pub(crate) noqa_line_for: &'a IntMap<usize, usize>,
pub(crate) locator: &'a SourceCodeLocator<'a>,
pub(crate) style: &'a SourceCodeStyleDetector<'a>,
// Computed checks.
checks: Vec<Check>,
// Function and class definition tracking (e.g., for docstring enforcement).
@@ -107,6 +110,7 @@ impl<'a> Checker<'a> {
noqa: flags::Noqa,
path: &'a Path,
locator: &'a SourceCodeLocator,
style: &'a SourceCodeStyleDetector,
) -> Checker<'a> {
Checker {
settings,
@@ -115,6 +119,7 @@ impl<'a> Checker<'a> {
noqa,
path,
locator,
style,
checks: vec![],
definitions: vec![],
deletions: FxHashSet::default(),
@@ -628,6 +633,15 @@ where
}
}
StmtKind::Import { names } => {
if self.settings.enabled.contains(&CheckCode::E401) {
if names.len() > 1 {
self.add_check(Check::new(
CheckKind::MultipleImportsOnOneLine,
Range::from_located(stmt),
));
}
}
if self.settings.enabled.contains(&CheckCode::E402) {
if self.seen_import_boundary && stmt.location.column() == 0 {
self.add_check(Check::new(
@@ -636,6 +650,9 @@ where
));
}
}
if self.settings.enabled.contains(&CheckCode::UP023) {
pyupgrade::plugins::replace_c_element_tree(self, stmt);
}
for alias in names {
if alias.node.name.contains('.') && alias.node.asname.is_none() {
@@ -805,6 +822,9 @@ where
} => {
// Track `import from` statements, to ensure that we can correctly attribute
// references like `from typing import Union`.
if self.settings.enabled.contains(&CheckCode::UP023) {
pyupgrade::plugins::replace_c_element_tree(self, stmt);
}
if level.map(|level| level == 0).unwrap_or(true) {
if let Some(module) = module {
self.from_imports
@@ -1058,17 +1078,11 @@ where
}
}
if self.settings.enabled.contains(&CheckCode::EM101)
| self.settings.enabled.contains(&CheckCode::EM102)
| self.settings.enabled.contains(&CheckCode::EM103)
|| self.settings.enabled.contains(&CheckCode::EM102)
|| self.settings.enabled.contains(&CheckCode::EM103)
{
if let Some(exc) = exc {
self.add_checks(
flake8_errmsg::checks::check_string_in_exception(
exc,
self.settings.flake8_errmsg.max_string_length,
)
.into_iter(),
);
flake8_errmsg::plugins::string_in_exception(self, exc);
}
}
}
@@ -1148,7 +1162,7 @@ where
if self.settings.enabled.contains(&CheckCode::B014)
|| self.settings.enabled.contains(&CheckCode::B025)
{
flake8_bugbear::plugins::duplicate_exceptions(self, stmt, handlers);
flake8_bugbear::plugins::duplicate_exceptions(self, handlers);
}
if self.settings.enabled.contains(&CheckCode::B013) {
flake8_bugbear::plugins::redundant_tuple_in_exception_handler(self, handlers);
@@ -1484,6 +1498,10 @@ where
ExprKind::Name { id, ctx } => {
match ctx {
ExprContext::Load => {
if self.settings.enabled.contains(&CheckCode::UP019) {
pyupgrade::plugins::typing_text_str_alias(self, expr);
}
// Ex) List[...]
if !self.in_deferred_string_type_definition
&& self.settings.enabled.contains(&CheckCode::UP006)
@@ -1544,6 +1562,14 @@ where
pyupgrade::plugins::remove_six_compat(self, expr);
}
if self.settings.enabled.contains(&CheckCode::UP017)
&& self.settings.target_version >= PythonVersion::Py311
{
pyupgrade::plugins::datetime_utc_alias(self, expr);
}
if self.settings.enabled.contains(&CheckCode::UP019) {
pyupgrade::plugins::typing_text_str_alias(self, expr);
}
if self.settings.enabled.contains(&CheckCode::YTT202) {
flake8_2020::plugins::name_or_attribute(self, expr);
}
@@ -1626,19 +1652,35 @@ where
}
// pyupgrade
if self.settings.enabled.contains(&CheckCode::UP003) {
pyupgrade::plugins::type_of_primitive(self, expr, func, args);
}
if self.settings.enabled.contains(&CheckCode::UP005) {
pyupgrade::plugins::deprecated_unittest_alias(self, func);
}
if self.settings.enabled.contains(&CheckCode::UP008) {
pyupgrade::plugins::super_call_with_parameters(self, expr, func, args);
}
if self.settings.enabled.contains(&CheckCode::UP012) {
pyupgrade::plugins::unnecessary_encode_utf8(self, expr, func, args, keywords);
}
if self.settings.enabled.contains(&CheckCode::UP015) {
pyupgrade::plugins::redundant_open_modes(self, expr);
}
if self.settings.enabled.contains(&CheckCode::UP016) {
pyupgrade::plugins::remove_six_compat(self, expr);
}
// flake8-super
if self.settings.enabled.contains(&CheckCode::UP008) {
pyupgrade::plugins::super_call_with_parameters(self, expr, func, args);
if self.settings.enabled.contains(&CheckCode::UP018) {
pyupgrade::plugins::native_literals(self, expr, func, args, keywords);
}
if self.settings.enabled.contains(&CheckCode::UP020) {
pyupgrade::plugins::open_alias(self, expr, func);
}
if self.settings.enabled.contains(&CheckCode::UP021) {
pyupgrade::plugins::replace_universal_newlines(self, expr, keywords);
}
if self.settings.enabled.contains(&CheckCode::UP022) {
pyupgrade::plugins::replace_stdout_stderr(self, expr, keywords);
}
// flake8-print
@@ -1703,7 +1745,6 @@ where
self.add_check(check);
};
}
if self.settings.enabled.contains(&CheckCode::C401) {
if let Some(check) = flake8_comprehensions::checks::unnecessary_generator_set(
expr,
@@ -1717,7 +1758,6 @@ where
self.add_check(check);
};
}
if self.settings.enabled.contains(&CheckCode::C402) {
if let Some(check) = flake8_comprehensions::checks::unnecessary_generator_dict(
expr,
@@ -1731,7 +1771,6 @@ where
self.add_check(check);
};
}
if self.settings.enabled.contains(&CheckCode::C403) {
if let Some(check) =
flake8_comprehensions::checks::unnecessary_list_comprehension_set(
@@ -1747,7 +1786,6 @@ where
self.add_check(check);
};
}
if self.settings.enabled.contains(&CheckCode::C404) {
if let Some(check) =
flake8_comprehensions::checks::unnecessary_list_comprehension_dict(
@@ -1763,7 +1801,6 @@ where
self.add_check(check);
};
}
if self.settings.enabled.contains(&CheckCode::C405) {
if let Some(check) = flake8_comprehensions::checks::unnecessary_literal_set(
expr,
@@ -1777,7 +1814,6 @@ where
self.add_check(check);
};
}
if self.settings.enabled.contains(&CheckCode::C406) {
if let Some(check) = flake8_comprehensions::checks::unnecessary_literal_dict(
expr,
@@ -1791,7 +1827,6 @@ where
self.add_check(check);
};
}
if self.settings.enabled.contains(&CheckCode::C408) {
if let Some(check) = flake8_comprehensions::checks::unnecessary_collection_call(
expr,
@@ -1805,7 +1840,6 @@ where
self.add_check(check);
};
}
if self.settings.enabled.contains(&CheckCode::C409) {
if let Some(check) =
flake8_comprehensions::checks::unnecessary_literal_within_tuple_call(
@@ -1820,7 +1854,6 @@ where
self.add_check(check);
};
}
if self.settings.enabled.contains(&CheckCode::C410) {
if let Some(check) =
flake8_comprehensions::checks::unnecessary_literal_within_list_call(
@@ -1835,7 +1868,6 @@ where
self.add_check(check);
};
}
if self.settings.enabled.contains(&CheckCode::C411) {
if let Some(check) = flake8_comprehensions::checks::unnecessary_list_call(
expr,
@@ -1848,7 +1880,6 @@ where
self.add_check(check);
};
}
if self.settings.enabled.contains(&CheckCode::C413) {
if let Some(check) =
flake8_comprehensions::checks::unnecessary_call_around_sorted(
@@ -1863,7 +1894,6 @@ where
self.add_check(check);
};
}
if self.settings.enabled.contains(&CheckCode::C414) {
if let Some(check) =
flake8_comprehensions::checks::unnecessary_double_cast_or_process(
@@ -1875,7 +1905,6 @@ where
self.add_check(check);
};
}
if self.settings.enabled.contains(&CheckCode::C415) {
if let Some(check) =
flake8_comprehensions::checks::unnecessary_subscript_reversal(
@@ -1887,7 +1916,6 @@ where
self.add_check(check);
};
}
if self.settings.enabled.contains(&CheckCode::C417) {
if let Some(check) = flake8_comprehensions::checks::unnecessary_map(
func,
@@ -1898,15 +1926,6 @@ where
};
}
// pyupgrade
if self.settings.enabled.contains(&CheckCode::UP003) {
pyupgrade::plugins::type_of_primitive(self, expr, func, args);
}
if self.settings.enabled.contains(&CheckCode::UP015) {
pyupgrade::plugins::redundant_open_modes(self, expr);
}
// flake8-boolean-trap
if self.settings.enabled.contains(&CheckCode::FBT003) {
flake8_boolean_trap::plugins::check_boolean_positional_value_in_function_call(
@@ -1937,7 +1956,6 @@ where
if self.settings.enabled.contains(&CheckCode::PD002) {
self.add_checks(pandas_vet::checks::inplace_argument(keywords).into_iter());
}
for (code, name) in vec![
(CheckCode::PD003, "isnull"),
(CheckCode::PD004, "notnull"),
@@ -1954,7 +1972,6 @@ where
}
}
}
if self.settings.enabled.contains(&CheckCode::PD015) {
if let Some(check) = pandas_vet::checks::use_of_pd_merge(func) {
self.add_check(check);
@@ -2048,6 +2065,14 @@ where
if self.settings.enabled.contains(&CheckCode::PLR1722) {
pylint::plugins::use_sys_exit(self, func);
}
// ruff
if self.settings.enabled.contains(&CheckCode::RUF004) {
self.add_checks(
ruff::checks::keyword_argument_before_star_argument(args, keywords)
.into_iter(),
);
}
}
ExprKind::Dict { keys, .. } => {
let check_repeated_literals = self.settings.enabled.contains(&CheckCode::F601);
@@ -2652,12 +2677,15 @@ where
self.check_builtin_shadowing(name, excepthandler, false);
let name_range =
helpers::excepthandler_name_range(excepthandler, self.locator).unwrap();
if self.current_scope().values.contains_key(&name.as_str()) {
self.handle_node_store(
name,
&Expr::new(
excepthandler.location,
excepthandler.end_location.unwrap(),
name_range.location,
name_range.end_location,
ExprKind::Name {
id: name.to_string(),
ctx: ExprContext::Store,
@@ -2670,8 +2698,8 @@ where
self.handle_node_store(
name,
&Expr::new(
excepthandler.location,
excepthandler.end_location.unwrap(),
name_range.location,
name_range.end_location,
ExprKind::Name {
id: name.to_string(),
ctx: ExprContext::Store,
@@ -2690,7 +2718,7 @@ where
if self.settings.enabled.contains(&CheckCode::F841) {
self.add_check(Check::new(
CheckKind::UnusedVariable(name.to_string()),
Range::from_located(excepthandler),
name_range,
));
}
}
@@ -3850,7 +3878,11 @@ impl<'a> Checker<'a> {
|| self.settings.enabled.contains(&CheckCode::D416)
|| self.settings.enabled.contains(&CheckCode::D417)
{
pydocstyle::plugins::sections(self, &docstring);
pydocstyle::plugins::sections(
self,
&docstring,
self.settings.pydocstyle.convention.as_ref(),
);
}
}
}
@@ -3893,16 +3925,26 @@ impl<'a> Checker<'a> {
}
}
#[allow(clippy::too_many_arguments)]
pub fn check_ast(
python_ast: &Suite,
locator: &SourceCodeLocator,
stylist: &SourceCodeStyleDetector,
noqa_line_for: &IntMap<usize, usize>,
settings: &Settings,
autofix: flags::Autofix,
noqa: flags::Noqa,
path: &Path,
) -> Vec<Check> {
let mut checker = Checker::new(settings, noqa_line_for, autofix, noqa, path, locator);
let mut checker = Checker::new(
settings,
noqa_line_for,
autofix,
noqa,
path,
locator,
stylist,
);
checker.push_scope(Scope::new(ScopeKind::Module));
checker.bind_builtins();

View File

@@ -55,7 +55,11 @@ pub fn check_lines(
}
if enforce_no_newline_at_end_of_file {
if let Some(check) = no_newline_at_end_of_file(contents) {
if let Some(check) = no_newline_at_end_of_file(
contents,
matches!(autofix, flags::Autofix::Enabled)
&& settings.fixable.contains(&CheckCode::W292),
) {
checks.push(check);
}
}

View File

@@ -1,11 +1,13 @@
//! `NoQA` enforcement and validation.
use std::str::FromStr;
use nohash_hasher::IntMap;
use rustpython_parser::ast::Location;
use crate::ast::types::Range;
use crate::autofix::Fix;
use crate::checks::{Check, CheckCode, CheckKind, CODE_REDIRECTS};
use crate::checks::{Check, CheckCode, CheckKind, UnusedCodes, CODE_REDIRECTS};
use crate::noqa;
use crate::noqa::{is_file_exempt, Directive};
use crate::settings::{flags, Settings};
@@ -98,18 +100,29 @@ pub fn check_noqa(
}
}
Directive::Codes(spaces, start, end, codes) => {
let mut invalid_codes = vec![];
let mut disabled_codes = vec![];
let mut unknown_codes = vec![];
let mut unmatched_codes = vec![];
let mut valid_codes = vec![];
let mut self_ignore = false;
for code in codes {
let code = CODE_REDIRECTS.get(code).map_or(code, AsRef::as_ref);
if code == CheckCode::RUF100.as_ref() {
self_ignore = true;
break;
}
if matches.contains(&code) || settings.external.contains(code) {
valid_codes.push(code);
} else {
if matches.contains(&code) || settings.external.contains(code) {
valid_codes.push(code);
if let Ok(check_code) = CheckCode::from_str(code) {
if settings.enabled.contains(&check_code) {
unmatched_codes.push(code);
} else {
disabled_codes.push(code);
}
} else {
invalid_codes.push(code);
unknown_codes.push(code);
}
}
}
@@ -118,14 +131,25 @@ pub fn check_noqa(
continue;
}
if !invalid_codes.is_empty() {
if !(disabled_codes.is_empty()
&& unknown_codes.is_empty()
&& unmatched_codes.is_empty())
{
let mut check = Check::new(
CheckKind::UnusedNOQA(Some(
invalid_codes
CheckKind::UnusedNOQA(Some(UnusedCodes {
disabled: disabled_codes
.iter()
.map(|code| (*code).to_string())
.collect(),
)),
unknown: unknown_codes
.iter()
.map(|code| (*code).to_string())
.collect(),
unmatched: unmatched_codes
.iter()
.map(|code| (*code).to_string())
.collect(),
})),
Range {
location: Location::new(row + 1, start),
end_location: Location::new(row + 1, end),

View File

@@ -89,7 +89,11 @@ pub fn check_tokens(
if enforce_invalid_escape_sequence {
if matches!(tok, Tok::String { .. }) {
checks.extend(pycodestyle::checks::invalid_escape_sequence(
locator, start, end,
locator,
start,
end,
matches!(autofix, flags::Autofix::Enabled)
&& settings.fixable.contains(&CheckCode::W605),
));
}
}

View File

@@ -1,5 +1,4 @@
use std::fmt;
use std::str::FromStr;
use itertools::Itertools;
use once_cell::sync::Lazy;
@@ -33,6 +32,7 @@ use crate::pyupgrade::types::Primitive;
)]
pub enum CheckCode {
// pycodestyle errors
E401,
E402,
E501,
E711,
@@ -224,6 +224,13 @@ pub enum CheckCode {
UP014,
UP015,
UP016,
UP017,
UP018,
UP019,
UP020,
UP021,
UP022,
UP023,
// pydocstyle
D100,
D101,
@@ -323,6 +330,7 @@ pub enum CheckCode {
RUF001,
RUF002,
RUF003,
RUF004,
RUF100,
// pygrep-hooks
PGH001,
@@ -633,6 +641,13 @@ impl fmt::Display for Branch {
}
}
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct UnusedCodes {
pub unknown: Vec<String>,
pub disabled: Vec<String>,
pub unmatched: Vec<String>,
}
#[derive(AsRefStr, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum CheckKind {
// pycodestyle errors
@@ -644,6 +659,7 @@ pub enum CheckKind {
IOError(String),
LineTooLong(usize, usize),
ModuleImportNotAtTopOfFile,
MultipleImportsOnOneLine,
NoneComparison(RejectedCmpop),
NotInTest,
NotIsTest,
@@ -812,6 +828,7 @@ pub enum CheckKind {
// pyupgrade
TypeOfPrimitive(Primitive),
UselessMetaclassType,
TypingTextStrAlias,
DeprecatedUnittestAlias(String, String),
UselessObjectInheritance(String),
UsePEP585Annotation(String),
@@ -825,6 +842,12 @@ pub enum CheckKind {
ConvertNamedTupleFunctionalToClass(String),
RedundantOpenModes,
RemoveSixCompat,
DatetimeTimezoneUTC,
NativeLiterals,
OpenAlias,
ReplaceUniversalNewlines,
ReplaceStdoutStderr,
RewriteCElementTree,
// pydocstyle
BlankLineAfterLastSection(String),
BlankLineAfterSection(String),
@@ -937,7 +960,8 @@ pub enum CheckKind {
AmbiguousUnicodeCharacterString(char, char),
AmbiguousUnicodeCharacterDocstring(char, char),
AmbiguousUnicodeCharacterComment(char, char),
UnusedNOQA(Option<Vec<String>>),
KeywordArgumentBeforeStarArgument(String),
UnusedNOQA(Option<UnusedCodes>),
// flake8-datetimez
CallDatetimeWithoutTzinfo,
CallDatetimeToday,
@@ -978,6 +1002,7 @@ impl CheckCode {
pub fn kind(&self) -> CheckKind {
match self {
// pycodestyle errors
CheckCode::E401 => CheckKind::MultipleImportsOnOneLine,
CheckCode::E402 => CheckKind::ModuleImportNotAtTopOfFile,
CheckCode::E501 => CheckKind::LineTooLong(89, 88),
CheckCode::E711 => CheckKind::NoneComparison(RejectedCmpop::Eq),
@@ -1197,6 +1222,13 @@ impl CheckCode {
CheckCode::UP014 => CheckKind::ConvertNamedTupleFunctionalToClass("...".to_string()),
CheckCode::UP015 => CheckKind::RedundantOpenModes,
CheckCode::UP016 => CheckKind::RemoveSixCompat,
CheckCode::UP017 => CheckKind::DatetimeTimezoneUTC,
CheckCode::UP018 => CheckKind::NativeLiterals,
CheckCode::UP019 => CheckKind::TypingTextStrAlias,
CheckCode::UP020 => CheckKind::OpenAlias,
CheckCode::UP021 => CheckKind::ReplaceUniversalNewlines,
CheckCode::UP022 => CheckKind::ReplaceStdoutStderr,
CheckCode::UP023 => CheckKind::RewriteCElementTree,
// pydocstyle
CheckCode::D100 => CheckKind::PublicModule,
CheckCode::D101 => CheckKind::PublicClass,
@@ -1336,6 +1368,7 @@ impl CheckCode {
CheckCode::RUF001 => CheckKind::AmbiguousUnicodeCharacterString('𝐁', 'B'),
CheckCode::RUF002 => CheckKind::AmbiguousUnicodeCharacterDocstring('𝐁', 'B'),
CheckCode::RUF003 => CheckKind::AmbiguousUnicodeCharacterComment('𝐁', 'B'),
CheckCode::RUF004 => CheckKind::KeywordArgumentBeforeStarArgument("...".to_string()),
CheckCode::RUF100 => CheckKind::UnusedNOQA(None),
}
}
@@ -1462,6 +1495,7 @@ impl CheckCode {
CheckCode::DTZ007 => CheckCategory::Flake8Datetimez,
CheckCode::DTZ011 => CheckCategory::Flake8Datetimez,
CheckCode::DTZ012 => CheckCategory::Flake8Datetimez,
CheckCode::E401 => CheckCategory::Pycodestyle,
CheckCode::E402 => CheckCategory::Pycodestyle,
CheckCode::E501 => CheckCategory::Pycodestyle,
CheckCode::E711 => CheckCategory::Pycodestyle,
@@ -1587,6 +1621,7 @@ impl CheckCode {
CheckCode::RUF001 => CheckCategory::Ruff,
CheckCode::RUF002 => CheckCategory::Ruff,
CheckCode::RUF003 => CheckCategory::Ruff,
CheckCode::RUF004 => CheckCategory::Ruff,
CheckCode::RUF100 => CheckCategory::Ruff,
CheckCode::S101 => CheckCategory::Flake8Bandit,
CheckCode::S102 => CheckCategory::Flake8Bandit,
@@ -1613,6 +1648,13 @@ impl CheckCode {
CheckCode::UP014 => CheckCategory::Pyupgrade,
CheckCode::UP015 => CheckCategory::Pyupgrade,
CheckCode::UP016 => CheckCategory::Pyupgrade,
CheckCode::UP017 => CheckCategory::Pyupgrade,
CheckCode::UP018 => CheckCategory::Pyupgrade,
CheckCode::UP019 => CheckCategory::Pyupgrade,
CheckCode::UP020 => CheckCategory::Pyupgrade,
CheckCode::UP021 => CheckCategory::Pyupgrade,
CheckCode::UP022 => CheckCategory::Pyupgrade,
CheckCode::UP023 => CheckCategory::Pyupgrade,
CheckCode::W292 => CheckCategory::Pycodestyle,
CheckCode::W605 => CheckCategory::Pycodestyle,
CheckCode::YTT101 => CheckCategory::Flake82020,
@@ -1634,9 +1676,9 @@ impl CheckKind {
pub fn code(&self) -> &'static CheckCode {
match self {
// pycodestyle errors
CheckKind::AmbiguousClassName(_) => &CheckCode::E742,
CheckKind::AmbiguousFunctionName(_) => &CheckCode::E743,
CheckKind::AmbiguousVariableName(_) => &CheckCode::E741,
CheckKind::AmbiguousClassName(..) => &CheckCode::E742,
CheckKind::AmbiguousFunctionName(..) => &CheckCode::E743,
CheckKind::AmbiguousVariableName(..) => &CheckCode::E741,
CheckKind::AssertTuple => &CheckCode::F631,
CheckKind::BreakOutsideLoop => &CheckCode::F701,
CheckKind::ContinueOutsideLoop => &CheckCode::F702,
@@ -1645,56 +1687,57 @@ impl CheckKind {
CheckKind::DoNotUseBareExcept => &CheckCode::E722,
CheckKind::DuplicateArgumentName => &CheckCode::F831,
CheckKind::FStringMissingPlaceholders => &CheckCode::F541,
CheckKind::ForwardAnnotationSyntaxError(_) => &CheckCode::F722,
CheckKind::FutureFeatureNotDefined(_) => &CheckCode::F407,
CheckKind::IOError(_) => &CheckCode::E902,
CheckKind::ForwardAnnotationSyntaxError(..) => &CheckCode::F722,
CheckKind::FutureFeatureNotDefined(..) => &CheckCode::F407,
CheckKind::IOError(..) => &CheckCode::E902,
CheckKind::IfTuple => &CheckCode::F634,
CheckKind::ImportShadowedByLoopVar(..) => &CheckCode::F402,
CheckKind::ImportStarNotPermitted(_) => &CheckCode::F406,
CheckKind::ImportStarNotPermitted(..) => &CheckCode::F406,
CheckKind::ImportStarUsage(..) => &CheckCode::F405,
CheckKind::ImportStarUsed(_) => &CheckCode::F403,
CheckKind::ImportStarUsed(..) => &CheckCode::F403,
CheckKind::InvalidPrintSyntax => &CheckCode::F633,
CheckKind::IsLiteral => &CheckCode::F632,
CheckKind::LateFutureImport => &CheckCode::F404,
CheckKind::LineTooLong(..) => &CheckCode::E501,
CheckKind::MultipleImportsOnOneLine => &CheckCode::E401,
CheckKind::ModuleImportNotAtTopOfFile => &CheckCode::E402,
CheckKind::MultiValueRepeatedKeyLiteral => &CheckCode::F601,
CheckKind::MultiValueRepeatedKeyVariable(_) => &CheckCode::F602,
CheckKind::NoneComparison(_) => &CheckCode::E711,
CheckKind::MultiValueRepeatedKeyVariable(..) => &CheckCode::F602,
CheckKind::NoneComparison(..) => &CheckCode::E711,
CheckKind::NotInTest => &CheckCode::E713,
CheckKind::NotIsTest => &CheckCode::E714,
CheckKind::PercentFormatExpectedMapping => &CheckCode::F502,
CheckKind::PercentFormatExpectedSequence => &CheckCode::F503,
CheckKind::PercentFormatExtraNamedArguments(_) => &CheckCode::F504,
CheckKind::PercentFormatInvalidFormat(_) => &CheckCode::F501,
CheckKind::PercentFormatMissingArgument(_) => &CheckCode::F505,
CheckKind::PercentFormatExtraNamedArguments(..) => &CheckCode::F504,
CheckKind::PercentFormatInvalidFormat(..) => &CheckCode::F501,
CheckKind::PercentFormatMissingArgument(..) => &CheckCode::F505,
CheckKind::PercentFormatMixedPositionalAndNamed => &CheckCode::F506,
CheckKind::PercentFormatPositionalCountMismatch(..) => &CheckCode::F507,
CheckKind::PercentFormatStarRequiresSequence => &CheckCode::F508,
CheckKind::PercentFormatUnsupportedFormatCharacter(_) => &CheckCode::F509,
CheckKind::PercentFormatUnsupportedFormatCharacter(..) => &CheckCode::F509,
CheckKind::RaiseNotImplemented => &CheckCode::F901,
CheckKind::ReturnOutsideFunction => &CheckCode::F706,
CheckKind::StringDotFormatExtraNamedArguments(_) => &CheckCode::F522,
CheckKind::StringDotFormatExtraPositionalArguments(_) => &CheckCode::F523,
CheckKind::StringDotFormatInvalidFormat(_) => &CheckCode::F521,
CheckKind::StringDotFormatMissingArguments(_) => &CheckCode::F524,
CheckKind::StringDotFormatExtraNamedArguments(..) => &CheckCode::F522,
CheckKind::StringDotFormatExtraPositionalArguments(..) => &CheckCode::F523,
CheckKind::StringDotFormatInvalidFormat(..) => &CheckCode::F521,
CheckKind::StringDotFormatMissingArguments(..) => &CheckCode::F524,
CheckKind::StringDotFormatMixingAutomatic => &CheckCode::F525,
CheckKind::SyntaxError(_) => &CheckCode::E999,
CheckKind::SyntaxError(..) => &CheckCode::E999,
CheckKind::ExpressionsInStarAssignment => &CheckCode::F621,
CheckKind::TrueFalseComparison(..) => &CheckCode::E712,
CheckKind::TwoStarredExpressions => &CheckCode::F622,
CheckKind::TypeComparison => &CheckCode::E721,
CheckKind::UndefinedExport(_) => &CheckCode::F822,
CheckKind::UndefinedLocal(_) => &CheckCode::F823,
CheckKind::UndefinedExport(..) => &CheckCode::F822,
CheckKind::UndefinedLocal(..) => &CheckCode::F823,
CheckKind::RedefinedWhileUnused(..) => &CheckCode::F811,
CheckKind::UndefinedName(_) => &CheckCode::F821,
CheckKind::UndefinedName(..) => &CheckCode::F821,
CheckKind::UnusedImport(..) => &CheckCode::F401,
CheckKind::UnusedVariable(_) => &CheckCode::F841,
CheckKind::UnusedAnnotation(_) => &CheckCode::F842,
CheckKind::YieldOutsideFunction(_) => &CheckCode::F704,
CheckKind::UnusedVariable(..) => &CheckCode::F841,
CheckKind::UnusedAnnotation(..) => &CheckCode::F842,
CheckKind::YieldOutsideFunction(..) => &CheckCode::F704,
// pycodestyle warnings
CheckKind::NoNewLineAtEndOfFile => &CheckCode::W292,
CheckKind::InvalidEscapeSequence(_) => &CheckCode::W605,
CheckKind::InvalidEscapeSequence(..) => &CheckCode::W605,
// pylint
CheckKind::AwaitOutsideAsync => &CheckCode::PLE1142,
CheckKind::ConsiderMergingIsinstance(..) => &CheckCode::PLR1701,
@@ -1703,96 +1746,96 @@ impl CheckKind {
CheckKind::MisplacedComparisonConstant(..) => &CheckCode::PLC2201,
CheckKind::PropertyWithParameters => &CheckCode::PLR0206,
CheckKind::UnnecessaryDirectLambdaCall => &CheckCode::PLC3002,
CheckKind::UseSysExit(_) => &CheckCode::PLR1722,
CheckKind::UseSysExit(..) => &CheckCode::PLR1722,
CheckKind::NonlocalWithoutBinding(..) => &CheckCode::PLE0117,
CheckKind::UsedPriorGlobalDeclaration(..) => &CheckCode::PLE0118,
CheckKind::UselessElseOnLoop => &CheckCode::PLW0120,
CheckKind::UselessImportAlias => &CheckCode::PLC0414,
// flake8-builtins
CheckKind::BuiltinVariableShadowing(_) => &CheckCode::A001,
CheckKind::BuiltinArgumentShadowing(_) => &CheckCode::A002,
CheckKind::BuiltinAttributeShadowing(_) => &CheckCode::A003,
CheckKind::BuiltinVariableShadowing(..) => &CheckCode::A001,
CheckKind::BuiltinArgumentShadowing(..) => &CheckCode::A002,
CheckKind::BuiltinAttributeShadowing(..) => &CheckCode::A003,
// flake8-bugbear
CheckKind::AbstractBaseClassWithoutAbstractMethod(_) => &CheckCode::B024,
CheckKind::AbstractBaseClassWithoutAbstractMethod(..) => &CheckCode::B024,
CheckKind::AssignmentToOsEnviron => &CheckCode::B003,
CheckKind::CachedInstanceMethod => &CheckCode::B019,
CheckKind::CannotRaiseLiteral => &CheckCode::B016,
CheckKind::DoNotAssertFalse => &CheckCode::B011,
CheckKind::DuplicateHandlerException(_) => &CheckCode::B014,
CheckKind::DuplicateTryBlockException(_) => &CheckCode::B025,
CheckKind::EmptyMethodWithoutAbstractDecorator(_) => &CheckCode::B027,
CheckKind::DuplicateHandlerException(..) => &CheckCode::B014,
CheckKind::DuplicateTryBlockException(..) => &CheckCode::B025,
CheckKind::EmptyMethodWithoutAbstractDecorator(..) => &CheckCode::B027,
CheckKind::FStringDocstring => &CheckCode::B021,
CheckKind::FunctionCallArgumentDefault(_) => &CheckCode::B008,
CheckKind::FunctionUsesLoopVariable(_) => &CheckCode::B023,
CheckKind::FunctionCallArgumentDefault(..) => &CheckCode::B008,
CheckKind::FunctionUsesLoopVariable(..) => &CheckCode::B023,
CheckKind::GetAttrWithConstant => &CheckCode::B009,
CheckKind::JumpStatementInFinally(_) => &CheckCode::B012,
CheckKind::LoopVariableOverridesIterator(_) => &CheckCode::B020,
CheckKind::JumpStatementInFinally(..) => &CheckCode::B012,
CheckKind::LoopVariableOverridesIterator(..) => &CheckCode::B020,
CheckKind::MutableArgumentDefault => &CheckCode::B006,
CheckKind::NoAssertRaisesException => &CheckCode::B017,
CheckKind::RaiseWithoutFromInsideExcept => &CheckCode::B904,
CheckKind::ZipWithoutExplicitStrict => &CheckCode::B905,
CheckKind::RedundantTupleInExceptionHandler(_) => &CheckCode::B013,
CheckKind::RedundantTupleInExceptionHandler(..) => &CheckCode::B013,
CheckKind::SetAttrWithConstant => &CheckCode::B010,
CheckKind::StarArgUnpackingAfterKeywordArg => &CheckCode::B026,
CheckKind::StripWithMultiCharacters => &CheckCode::B005,
CheckKind::UnaryPrefixIncrement => &CheckCode::B002,
CheckKind::UnreliableCallableCheck => &CheckCode::B004,
CheckKind::UnusedLoopControlVariable(_) => &CheckCode::B007,
CheckKind::UnusedLoopControlVariable(..) => &CheckCode::B007,
CheckKind::UselessComparison => &CheckCode::B015,
CheckKind::UselessContextlibSuppress => &CheckCode::B022,
CheckKind::UselessExpression => &CheckCode::B018,
// flake8-blind-except
CheckKind::BlindExcept(_) => &CheckCode::BLE001,
CheckKind::BlindExcept(..) => &CheckCode::BLE001,
// flake8-comprehensions
CheckKind::UnnecessaryGeneratorList => &CheckCode::C400,
CheckKind::UnnecessaryGeneratorSet => &CheckCode::C401,
CheckKind::UnnecessaryGeneratorDict => &CheckCode::C402,
CheckKind::UnnecessaryListComprehensionSet => &CheckCode::C403,
CheckKind::UnnecessaryListComprehensionDict => &CheckCode::C404,
CheckKind::UnnecessaryLiteralSet(_) => &CheckCode::C405,
CheckKind::UnnecessaryLiteralDict(_) => &CheckCode::C406,
CheckKind::UnnecessaryCollectionCall(_) => &CheckCode::C408,
CheckKind::UnnecessaryLiteralSet(..) => &CheckCode::C405,
CheckKind::UnnecessaryLiteralDict(..) => &CheckCode::C406,
CheckKind::UnnecessaryCollectionCall(..) => &CheckCode::C408,
CheckKind::UnnecessaryLiteralWithinTupleCall(..) => &CheckCode::C409,
CheckKind::UnnecessaryLiteralWithinListCall(..) => &CheckCode::C410,
CheckKind::UnnecessaryListCall => &CheckCode::C411,
CheckKind::UnnecessaryCallAroundSorted(_) => &CheckCode::C413,
CheckKind::UnnecessaryCallAroundSorted(..) => &CheckCode::C413,
CheckKind::UnnecessaryDoubleCastOrProcess(..) => &CheckCode::C414,
CheckKind::UnnecessarySubscriptReversal(_) => &CheckCode::C415,
CheckKind::UnnecessarySubscriptReversal(..) => &CheckCode::C415,
CheckKind::UnnecessaryComprehension(..) => &CheckCode::C416,
CheckKind::UnnecessaryMap(_) => &CheckCode::C417,
CheckKind::UnnecessaryMap(..) => &CheckCode::C417,
// flake8-debugger
CheckKind::Debugger(_) => &CheckCode::T100,
CheckKind::Debugger(..) => &CheckCode::T100,
// flake8-tidy-imports
CheckKind::BannedRelativeImport(_) => &CheckCode::TID252,
CheckKind::BannedRelativeImport(..) => &CheckCode::TID252,
// flake8-return
CheckKind::UnnecessaryReturnNone => &CheckCode::RET501,
CheckKind::ImplicitReturnValue => &CheckCode::RET502,
CheckKind::ImplicitReturn => &CheckCode::RET503,
CheckKind::UnnecessaryAssign => &CheckCode::RET504,
CheckKind::SuperfluousElseReturn(_) => &CheckCode::RET505,
CheckKind::SuperfluousElseRaise(_) => &CheckCode::RET506,
CheckKind::SuperfluousElseContinue(_) => &CheckCode::RET507,
CheckKind::SuperfluousElseBreak(_) => &CheckCode::RET508,
CheckKind::SuperfluousElseReturn(..) => &CheckCode::RET505,
CheckKind::SuperfluousElseRaise(..) => &CheckCode::RET506,
CheckKind::SuperfluousElseContinue(..) => &CheckCode::RET507,
CheckKind::SuperfluousElseBreak(..) => &CheckCode::RET508,
// flake8-print
CheckKind::PrintFound => &CheckCode::T201,
CheckKind::PPrintFound => &CheckCode::T203,
// flake8-quotes
CheckKind::BadQuotesInlineString(_) => &CheckCode::Q000,
CheckKind::BadQuotesMultilineString(_) => &CheckCode::Q001,
CheckKind::BadQuotesDocstring(_) => &CheckCode::Q002,
CheckKind::BadQuotesInlineString(..) => &CheckCode::Q000,
CheckKind::BadQuotesMultilineString(..) => &CheckCode::Q001,
CheckKind::BadQuotesDocstring(..) => &CheckCode::Q002,
CheckKind::AvoidQuoteEscape => &CheckCode::Q003,
// flake8-annotations
CheckKind::MissingTypeFunctionArgument(_) => &CheckCode::ANN001,
CheckKind::MissingTypeArgs(_) => &CheckCode::ANN002,
CheckKind::MissingTypeKwargs(_) => &CheckCode::ANN003,
CheckKind::MissingTypeSelf(_) => &CheckCode::ANN101,
CheckKind::MissingTypeCls(_) => &CheckCode::ANN102,
CheckKind::MissingReturnTypePublicFunction(_) => &CheckCode::ANN201,
CheckKind::MissingReturnTypePrivateFunction(_) => &CheckCode::ANN202,
CheckKind::MissingReturnTypeSpecialMethod(_) => &CheckCode::ANN204,
CheckKind::MissingReturnTypeStaticMethod(_) => &CheckCode::ANN205,
CheckKind::MissingReturnTypeClassMethod(_) => &CheckCode::ANN206,
CheckKind::DynamicallyTypedExpression(_) => &CheckCode::ANN401,
CheckKind::MissingTypeFunctionArgument(..) => &CheckCode::ANN001,
CheckKind::MissingTypeArgs(..) => &CheckCode::ANN002,
CheckKind::MissingTypeKwargs(..) => &CheckCode::ANN003,
CheckKind::MissingTypeSelf(..) => &CheckCode::ANN101,
CheckKind::MissingTypeCls(..) => &CheckCode::ANN102,
CheckKind::MissingReturnTypePublicFunction(..) => &CheckCode::ANN201,
CheckKind::MissingReturnTypePrivateFunction(..) => &CheckCode::ANN202,
CheckKind::MissingReturnTypeSpecialMethod(..) => &CheckCode::ANN204,
CheckKind::MissingReturnTypeStaticMethod(..) => &CheckCode::ANN205,
CheckKind::MissingReturnTypeClassMethod(..) => &CheckCode::ANN206,
CheckKind::DynamicallyTypedExpression(..) => &CheckCode::ANN401,
// flake8-2020
CheckKind::SysVersionSlice3Referenced => &CheckCode::YTT101,
CheckKind::SysVersion2Referenced => &CheckCode::YTT102,
@@ -1807,28 +1850,35 @@ impl CheckKind {
// flake8-simplify
CheckKind::KeyInDict(..) => &CheckCode::SIM118,
// pyupgrade
CheckKind::TypeOfPrimitive(_) => &CheckCode::UP003,
CheckKind::TypeOfPrimitive(..) => &CheckCode::UP003,
CheckKind::UselessMetaclassType => &CheckCode::UP001,
CheckKind::DeprecatedUnittestAlias(..) => &CheckCode::UP005,
CheckKind::UsePEP585Annotation(_) => &CheckCode::UP006,
CheckKind::UsePEP585Annotation(..) => &CheckCode::UP006,
CheckKind::UsePEP604Annotation => &CheckCode::UP007,
CheckKind::UselessObjectInheritance(_) => &CheckCode::UP004,
CheckKind::UselessObjectInheritance(..) => &CheckCode::UP004,
CheckKind::SuperCallWithParameters => &CheckCode::UP008,
CheckKind::PEP3120UnnecessaryCodingComment => &CheckCode::UP009,
CheckKind::UnnecessaryFutureImport(_) => &CheckCode::UP010,
CheckKind::UnnecessaryFutureImport(..) => &CheckCode::UP010,
CheckKind::UnnecessaryLRUCacheParams => &CheckCode::UP011,
CheckKind::UnnecessaryEncodeUTF8 => &CheckCode::UP012,
CheckKind::ConvertTypedDictFunctionalToClass(_) => &CheckCode::UP013,
CheckKind::ConvertNamedTupleFunctionalToClass(_) => &CheckCode::UP014,
CheckKind::ConvertTypedDictFunctionalToClass(..) => &CheckCode::UP013,
CheckKind::ConvertNamedTupleFunctionalToClass(..) => &CheckCode::UP014,
CheckKind::RedundantOpenModes => &CheckCode::UP015,
CheckKind::RemoveSixCompat => &CheckCode::UP016,
CheckKind::DatetimeTimezoneUTC => &CheckCode::UP017,
CheckKind::NativeLiterals => &CheckCode::UP018,
CheckKind::TypingTextStrAlias => &CheckCode::UP019,
CheckKind::OpenAlias => &CheckCode::UP020,
CheckKind::ReplaceUniversalNewlines => &CheckCode::UP021,
CheckKind::ReplaceStdoutStderr => &CheckCode::UP022,
CheckKind::RewriteCElementTree => &CheckCode::UP023,
// pydocstyle
CheckKind::BlankLineAfterLastSection(_) => &CheckCode::D413,
CheckKind::BlankLineAfterSection(_) => &CheckCode::D410,
CheckKind::BlankLineBeforeSection(_) => &CheckCode::D411,
CheckKind::CapitalizeSectionName(_) => &CheckCode::D405,
CheckKind::DashedUnderlineAfterSection(_) => &CheckCode::D407,
CheckKind::DocumentAllArguments(_) => &CheckCode::D417,
CheckKind::BlankLineAfterLastSection(..) => &CheckCode::D413,
CheckKind::BlankLineAfterSection(..) => &CheckCode::D410,
CheckKind::BlankLineBeforeSection(..) => &CheckCode::D411,
CheckKind::CapitalizeSectionName(..) => &CheckCode::D405,
CheckKind::DashedUnderlineAfterSection(..) => &CheckCode::D407,
CheckKind::DocumentAllArguments(..) => &CheckCode::D417,
CheckKind::EndsInPeriod => &CheckCode::D400,
CheckKind::EndsInPunctuation => &CheckCode::D415,
CheckKind::FirstLineCapitalized => &CheckCode::D403,
@@ -1838,21 +1888,21 @@ impl CheckKind {
CheckKind::MultiLineSummaryFirstLine => &CheckCode::D212,
CheckKind::MultiLineSummarySecondLine => &CheckCode::D213,
CheckKind::NewLineAfterLastParagraph => &CheckCode::D209,
CheckKind::NewLineAfterSectionName(_) => &CheckCode::D406,
CheckKind::NoBlankLineAfterFunction(_) => &CheckCode::D202,
CheckKind::NewLineAfterSectionName(..) => &CheckCode::D406,
CheckKind::NoBlankLineAfterFunction(..) => &CheckCode::D202,
CheckKind::BlankLineAfterSummary => &CheckCode::D205,
CheckKind::NoBlankLineBeforeClass(_) => &CheckCode::D211,
CheckKind::NoBlankLineBeforeFunction(_) => &CheckCode::D201,
CheckKind::NoBlankLinesBetweenHeaderAndContent(_) => &CheckCode::D412,
CheckKind::NoBlankLineBeforeClass(..) => &CheckCode::D211,
CheckKind::NoBlankLineBeforeFunction(..) => &CheckCode::D201,
CheckKind::NoBlankLinesBetweenHeaderAndContent(..) => &CheckCode::D412,
CheckKind::NoOverIndentation => &CheckCode::D208,
CheckKind::NoSignature => &CheckCode::D402,
CheckKind::NoSurroundingWhitespace => &CheckCode::D210,
CheckKind::NoThisPrefix => &CheckCode::D404,
CheckKind::NoUnderIndentation => &CheckCode::D207,
CheckKind::NonEmpty => &CheckCode::D419,
CheckKind::NonEmptySection(_) => &CheckCode::D414,
CheckKind::OneBlankLineAfterClass(_) => &CheckCode::D204,
CheckKind::OneBlankLineBeforeClass(_) => &CheckCode::D203,
CheckKind::NonEmptySection(..) => &CheckCode::D414,
CheckKind::OneBlankLineAfterClass(..) => &CheckCode::D204,
CheckKind::OneBlankLineBeforeClass(..) => &CheckCode::D203,
CheckKind::PublicClass => &CheckCode::D101,
CheckKind::PublicFunction => &CheckCode::D103,
CheckKind::PublicInit => &CheckCode::D107,
@@ -1860,18 +1910,18 @@ impl CheckKind {
CheckKind::PublicModule => &CheckCode::D100,
CheckKind::PublicNestedClass => &CheckCode::D106,
CheckKind::PublicPackage => &CheckCode::D104,
CheckKind::SectionNameEndsInColon(_) => &CheckCode::D416,
CheckKind::SectionNotOverIndented(_) => &CheckCode::D214,
CheckKind::SectionUnderlineAfterName(_) => &CheckCode::D408,
CheckKind::SectionUnderlineMatchesSectionLength(_) => &CheckCode::D409,
CheckKind::SectionUnderlineNotOverIndented(_) => &CheckCode::D215,
CheckKind::SectionNameEndsInColon(..) => &CheckCode::D416,
CheckKind::SectionNotOverIndented(..) => &CheckCode::D214,
CheckKind::SectionUnderlineAfterName(..) => &CheckCode::D408,
CheckKind::SectionUnderlineMatchesSectionLength(..) => &CheckCode::D409,
CheckKind::SectionUnderlineNotOverIndented(..) => &CheckCode::D215,
CheckKind::SkipDocstring => &CheckCode::D418,
CheckKind::UsesRPrefixForBackslashedContent => &CheckCode::D301,
CheckKind::UsesTripleQuotes => &CheckCode::D300,
// pep8-naming
CheckKind::InvalidClassName(_) => &CheckCode::N801,
CheckKind::InvalidFunctionName(_) => &CheckCode::N802,
CheckKind::InvalidArgumentName(_) => &CheckCode::N803,
CheckKind::InvalidClassName(..) => &CheckCode::N801,
CheckKind::InvalidFunctionName(..) => &CheckCode::N802,
CheckKind::InvalidArgumentName(..) => &CheckCode::N803,
CheckKind::InvalidFirstArgumentNameForClassMethod => &CheckCode::N804,
CheckKind::InvalidFirstArgumentNameForMethod => &CheckCode::N805,
CheckKind::NonLowercaseVariableInFunction(..) => &CheckCode::N806,
@@ -1944,7 +1994,8 @@ impl CheckKind {
CheckKind::AmbiguousUnicodeCharacterString(..) => &CheckCode::RUF001,
CheckKind::AmbiguousUnicodeCharacterDocstring(..) => &CheckCode::RUF002,
CheckKind::AmbiguousUnicodeCharacterComment(..) => &CheckCode::RUF003,
CheckKind::UnusedNOQA(_) => &CheckCode::RUF100,
CheckKind::KeywordArgumentBeforeStarArgument(..) => &CheckCode::RUF004,
CheckKind::UnusedNOQA(..) => &CheckCode::RUF100,
}
}
@@ -2016,6 +2067,7 @@ impl CheckKind {
CheckKind::ModuleImportNotAtTopOfFile => {
"Module level import not at top of file".to_string()
}
CheckKind::MultipleImportsOnOneLine => "Multiple imports on one line".to_string(),
CheckKind::MultiValueRepeatedKeyLiteral => {
"Dictionary key literal repeated".to_string()
}
@@ -2511,8 +2563,9 @@ impl CheckKind {
format!("Use `{}` instead of `type(...)`", primitive.builtin())
}
CheckKind::UselessMetaclassType => "`__metaclass__ = type` is implied".to_string(),
CheckKind::TypingTextStrAlias => "`typing.Text` is deprecated, use `str`".to_string(),
CheckKind::DeprecatedUnittestAlias(alias, target) => {
format!("`{alias}` is deprecated, use `{target}` instead")
format!("`{alias}` is deprecated, use `{target}`")
}
CheckKind::UselessObjectInheritance(name) => {
format!("Class `{name}` inherits from object")
@@ -2543,9 +2596,21 @@ impl CheckKind {
CheckKind::UnnecessaryEncodeUTF8 => "Unnecessary call to `encode` as UTF-8".to_string(),
CheckKind::RedundantOpenModes => "Unnecessary open mode parameters".to_string(),
CheckKind::RemoveSixCompat => "Unnecessary `six` compatibility usage".to_string(),
CheckKind::DatetimeTimezoneUTC => "Use `datetime.UTC` alias".to_string(),
CheckKind::NativeLiterals => "Unnecessary call to `str` and `bytes`".to_string(),
CheckKind::OpenAlias => "Use builtin `open`".to_string(),
CheckKind::ConvertTypedDictFunctionalToClass(name) => {
format!("Convert `{name}` from `TypedDict` functional to class syntax")
}
CheckKind::ReplaceUniversalNewlines => {
"`universal_newlines` is deprecated, use `text`".to_string()
}
CheckKind::ReplaceStdoutStderr => {
"Sending stdout and stderr to pipe is deprecated, use `capture_output`".to_string()
}
CheckKind::RewriteCElementTree => {
"`cElementTree` is deprecated, use `ElementTree`".to_string()
}
CheckKind::ConvertNamedTupleFunctionalToClass(name) => {
format!("Convert `{name}` from `NamedTuple` functional to class syntax")
}
@@ -2587,13 +2652,13 @@ impl CheckKind {
CheckKind::NoBlankLineAfterFunction(num_lines) => {
format!("No blank lines allowed after function docstring (found {num_lines})")
}
CheckKind::NoBlankLineBeforeClass(_) => {
CheckKind::NoBlankLineBeforeClass(..) => {
"No blank lines allowed before class docstring".to_string()
}
CheckKind::OneBlankLineBeforeClass(_) => {
CheckKind::OneBlankLineBeforeClass(..) => {
"1 blank line required before class docstring".to_string()
}
CheckKind::OneBlankLineAfterClass(_) => {
CheckKind::OneBlankLineAfterClass(..) => {
"1 blank line required after class docstring".to_string()
}
CheckKind::PublicModule => "Missing docstring in public module".to_string(),
@@ -2838,20 +2903,48 @@ impl CheckKind {
'{representant}'?)"
)
}
CheckKind::KeywordArgumentBeforeStarArgument(name) => {
format!("Keyword argument `{name}` must come after starred arguments")
}
CheckKind::UnusedNOQA(codes) => match codes {
None => "Unused `noqa` directive".to_string(),
None => "Unused blanket `noqa` directive".to_string(),
Some(codes) => {
let codes = codes
.iter()
.map(|code| {
if CheckCode::from_str(code).is_ok() {
code.to_string()
} else {
format!("{code} (not implemented)")
}
})
.join(", ");
format!("Unused `noqa` directive for: {codes}")
let mut codes_by_reason = vec![];
if !codes.unmatched.is_empty() {
codes_by_reason.push(format!(
"unused: {}",
codes
.unmatched
.iter()
.map(|code| format!("`{code}`"))
.join(", ")
));
}
if !codes.disabled.is_empty() {
codes_by_reason.push(format!(
"non-enabled: {}",
codes
.disabled
.iter()
.map(|code| format!("`{code}`"))
.join(", ")
));
}
if !codes.unknown.is_empty() {
codes_by_reason.push(format!(
"unknown: {}",
codes
.unknown
.iter()
.map(|code| format!("`{code}`"))
.join(", ")
));
}
if codes_by_reason.is_empty() {
"Unused `noqa` directive".to_string()
} else {
format!("Unused `noqa` directive ({})", codes_by_reason.join("; "))
}
}
},
// flake8-datetimez
@@ -2944,6 +3037,7 @@ impl CheckKind {
| CheckKind::ConvertNamedTupleFunctionalToClass(..)
| CheckKind::ConvertTypedDictFunctionalToClass(..)
| CheckKind::DashedUnderlineAfterSection(..)
| CheckKind::DatetimeTimezoneUTC
| CheckKind::DeprecatedUnittestAlias(..)
| CheckKind::DoNotAssertFalse
| CheckKind::DoNotAssignLambda
@@ -2953,16 +3047,23 @@ impl CheckKind {
| CheckKind::GetAttrWithConstant
| CheckKind::ImplicitReturn
| CheckKind::ImplicitReturnValue
| CheckKind::InvalidEscapeSequence(..)
| CheckKind::IsLiteral
| CheckKind::KeyInDict(..)
| CheckKind::MisplacedComparisonConstant(..)
| CheckKind::MissingReturnTypeSpecialMethod(..)
| CheckKind::NativeLiterals
| CheckKind::OpenAlias
| CheckKind::NewLineAfterLastParagraph
| CheckKind::ReplaceUniversalNewlines
| CheckKind::ReplaceStdoutStderr
| CheckKind::RewriteCElementTree
| CheckKind::NewLineAfterSectionName(..)
| CheckKind::NoBlankLineAfterFunction(..)
| CheckKind::NoBlankLineBeforeClass(..)
| CheckKind::NoBlankLineBeforeFunction(..)
| CheckKind::NoBlankLinesBetweenHeaderAndContent(..)
| CheckKind::NoNewLineAtEndOfFile
| CheckKind::NoOverIndentation
| CheckKind::NoSurroundingWhitespace
| CheckKind::NoUnderIndentation
@@ -2989,6 +3090,7 @@ impl CheckKind {
| CheckKind::SuperCallWithParameters
| CheckKind::TrueFalseComparison(..)
| CheckKind::TypeOfPrimitive(..)
| CheckKind::TypingTextStrAlias
| CheckKind::UnnecessaryCallAroundSorted(..)
| CheckKind::UnnecessaryCollectionCall(..)
| CheckKind::UnnecessaryComprehension(..)
@@ -3043,6 +3145,82 @@ impl Check {
}
}
/// A hash map from deprecated `CheckCodePrefix` to latest `CheckCodePrefix`.
pub static PREFIX_REDIRECTS: Lazy<FxHashMap<&'static str, CheckCodePrefix>> = Lazy::new(|| {
FxHashMap::from_iter([
// TODO(charlie): Remove by 2023-01-01.
("U001", CheckCodePrefix::UP001),
("U003", CheckCodePrefix::UP003),
("U004", CheckCodePrefix::UP004),
("U005", CheckCodePrefix::UP005),
("U006", CheckCodePrefix::UP006),
("U007", CheckCodePrefix::UP007),
("U008", CheckCodePrefix::UP008),
("U009", CheckCodePrefix::UP009),
("U010", CheckCodePrefix::UP010),
("U011", CheckCodePrefix::UP011),
("U012", CheckCodePrefix::UP012),
("U013", CheckCodePrefix::UP013),
("U014", CheckCodePrefix::UP014),
("U015", CheckCodePrefix::UP015),
("U016", CheckCodePrefix::UP016),
("U017", CheckCodePrefix::UP017),
("U019", CheckCodePrefix::UP019),
// TODO(charlie): Remove by 2023-02-01.
("I252", CheckCodePrefix::TID252),
("M001", CheckCodePrefix::RUF100),
// TODO(charlie): Remove by 2023-02-01.
("PDV002", CheckCodePrefix::PD002),
("PDV003", CheckCodePrefix::PD003),
("PDV004", CheckCodePrefix::PD004),
("PDV007", CheckCodePrefix::PD007),
("PDV008", CheckCodePrefix::PD008),
("PDV009", CheckCodePrefix::PD009),
("PDV010", CheckCodePrefix::PD010),
("PDV011", CheckCodePrefix::PD011),
("PDV012", CheckCodePrefix::PD012),
("PDV013", CheckCodePrefix::PD013),
("PDV015", CheckCodePrefix::PD015),
("PDV901", CheckCodePrefix::PD901),
// TODO(charlie): Remove by 2023-02-01.
("R501", CheckCodePrefix::RET501),
("R502", CheckCodePrefix::RET502),
("R503", CheckCodePrefix::RET503),
("R504", CheckCodePrefix::RET504),
("R505", CheckCodePrefix::RET505),
("R506", CheckCodePrefix::RET506),
("R507", CheckCodePrefix::RET507),
("R508", CheckCodePrefix::RET508),
("IC001", CheckCodePrefix::ICN001),
("IC002", CheckCodePrefix::ICN001),
("IC003", CheckCodePrefix::ICN001),
("IC004", CheckCodePrefix::ICN001),
// TODO(charlie): Remove by 2023-01-01.
("U", CheckCodePrefix::UP),
("U0", CheckCodePrefix::UP0),
("U00", CheckCodePrefix::UP00),
("U01", CheckCodePrefix::UP01),
// TODO(charlie): Remove by 2023-02-01.
("I2", CheckCodePrefix::TID2),
("I25", CheckCodePrefix::TID25),
("M", CheckCodePrefix::RUF100),
("M0", CheckCodePrefix::RUF100),
// TODO(charlie): Remove by 2023-02-01.
("PDV", CheckCodePrefix::PD),
("PDV0", CheckCodePrefix::PD0),
("PDV01", CheckCodePrefix::PD01),
("PDV9", CheckCodePrefix::PD9),
("PDV90", CheckCodePrefix::PD90),
// TODO(charlie): Remove by 2023-02-01.
("R", CheckCodePrefix::RET),
("R5", CheckCodePrefix::RET5),
("R50", CheckCodePrefix::RET50),
// TODO(charlie): Remove by 2023-02-01.
("IC", CheckCodePrefix::ICN),
("IC0", CheckCodePrefix::ICN0),
])
});
/// A hash map from deprecated to latest `CheckCode`.
pub static CODE_REDIRECTS: Lazy<FxHashMap<&'static str, CheckCode>> = Lazy::new(|| {
FxHashMap::from_iter([
@@ -3062,6 +3240,8 @@ pub static CODE_REDIRECTS: Lazy<FxHashMap<&'static str, CheckCode>> = Lazy::new(
("U014", CheckCode::UP014),
("U015", CheckCode::UP015),
("U016", CheckCode::UP016),
("U017", CheckCode::UP017),
("U019", CheckCode::UP019),
// TODO(charlie): Remove by 2023-02-01.
("I252", CheckCode::TID252),
("M001", CheckCode::RUF100),
@@ -3078,28 +3258,20 @@ pub static CODE_REDIRECTS: Lazy<FxHashMap<&'static str, CheckCode>> = Lazy::new(
("PDV013", CheckCode::PD013),
("PDV015", CheckCode::PD015),
("PDV901", CheckCode::PD901),
])
});
/// A hash map from deprecated `CheckCodePrefix` to latest `CheckCodePrefix`.
pub static PREFIX_REDIRECTS: Lazy<FxHashMap<&'static str, &'static str>> = Lazy::new(|| {
FxHashMap::from_iter([
// TODO(charlie): Remove by 2023-01-01.
("U", "UP"),
("U0", "UP0"),
("U00", "UP00"),
("U01", "UP01"),
// TODO(charlie): Remove by 2023-02-01.
("I2", "TID2"),
("I25", "TID25"),
("M", "RUF100"),
("M0", "RUF100"),
("R501", CheckCode::RET501),
("R502", CheckCode::RET502),
("R503", CheckCode::RET503),
("R504", CheckCode::RET504),
("R505", CheckCode::RET505),
("R506", CheckCode::RET506),
("R507", CheckCode::RET507),
("R508", CheckCode::RET508),
// TODO(charlie): Remove by 2023-02-01.
("PDV", "PD"),
("PDV0", "PD0"),
("PDV01", "PD01"),
("PDV9", "PD9"),
("PDV90", "PD90"),
("IC001", CheckCode::ICN001),
("IC002", CheckCode::ICN001),
("IC003", CheckCode::ICN001),
("IC004", CheckCode::ICN001),
])
});

View File

@@ -1,6 +1,7 @@
//! File automatically generated by `examples/generate_check_code_prefix.rs`.
use colored::Colorize;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use strum_macros::{AsRefStr, EnumString};
@@ -8,7 +9,17 @@ use crate::checks::CheckCode;
use crate::one_time_warning;
#[derive(
EnumString, AsRefStr, Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Serialize, Deserialize,
EnumString,
AsRefStr,
Debug,
PartialEq,
Eq,
PartialOrd,
Ord,
Clone,
Serialize,
Deserialize,
JsonSchema,
)]
pub enum CheckCodePrefix {
A,
@@ -17,6 +28,7 @@ pub enum CheckCodePrefix {
A001,
A002,
A003,
ALL,
ANN,
ANN0,
ANN00,
@@ -179,6 +191,7 @@ pub enum CheckCodePrefix {
E,
E4,
E40,
E401,
E402,
E5,
E50,
@@ -291,6 +304,12 @@ pub enum CheckCodePrefix {
I2,
I25,
I252,
IC,
IC0,
IC001,
IC002,
IC003,
IC004,
ICN,
ICN0,
ICN00,
@@ -410,6 +429,17 @@ pub enum CheckCodePrefix {
Q001,
Q002,
Q003,
R,
R5,
R50,
R501,
R502,
R503,
R504,
R505,
R506,
R507,
R508,
RET,
RET5,
RET50,
@@ -427,6 +457,7 @@ pub enum CheckCodePrefix {
RUF001,
RUF002,
RUF003,
RUF004,
RUF1,
RUF10,
RUF100,
@@ -474,6 +505,8 @@ pub enum CheckCodePrefix {
U014,
U015,
U016,
U017,
U019,
UP,
UP0,
UP00,
@@ -493,6 +526,14 @@ pub enum CheckCodePrefix {
UP014,
UP015,
UP016,
UP017,
UP018,
UP019,
UP02,
UP020,
UP021,
UP022,
UP023,
W,
W2,
W29,
@@ -521,6 +562,7 @@ pub enum CheckCodePrefix {
#[derive(PartialEq, Eq, PartialOrd, Ord)]
pub enum SuffixLength {
None,
Zero,
One,
Two,
@@ -538,6 +580,299 @@ impl CheckCodePrefix {
CheckCodePrefix::A001 => vec![CheckCode::A001],
CheckCodePrefix::A002 => vec![CheckCode::A002],
CheckCodePrefix::A003 => vec![CheckCode::A003],
CheckCodePrefix::ALL => vec![
CheckCode::E401,
CheckCode::E402,
CheckCode::E501,
CheckCode::E711,
CheckCode::E712,
CheckCode::E713,
CheckCode::E714,
CheckCode::E721,
CheckCode::E722,
CheckCode::E731,
CheckCode::E741,
CheckCode::E742,
CheckCode::E743,
CheckCode::E902,
CheckCode::E999,
CheckCode::W292,
CheckCode::W605,
CheckCode::F401,
CheckCode::F402,
CheckCode::F403,
CheckCode::F404,
CheckCode::F405,
CheckCode::F406,
CheckCode::F407,
CheckCode::F501,
CheckCode::F502,
CheckCode::F503,
CheckCode::F504,
CheckCode::F505,
CheckCode::F506,
CheckCode::F507,
CheckCode::F508,
CheckCode::F509,
CheckCode::F521,
CheckCode::F522,
CheckCode::F523,
CheckCode::F524,
CheckCode::F525,
CheckCode::F541,
CheckCode::F601,
CheckCode::F602,
CheckCode::F621,
CheckCode::F622,
CheckCode::F631,
CheckCode::F632,
CheckCode::F633,
CheckCode::F634,
CheckCode::F701,
CheckCode::F702,
CheckCode::F704,
CheckCode::F706,
CheckCode::F707,
CheckCode::F722,
CheckCode::F811,
CheckCode::F821,
CheckCode::F822,
CheckCode::F823,
CheckCode::F831,
CheckCode::F841,
CheckCode::F842,
CheckCode::F901,
CheckCode::PLC0414,
CheckCode::PLC2201,
CheckCode::PLC3002,
CheckCode::PLE0117,
CheckCode::PLE0118,
CheckCode::PLE1142,
CheckCode::PLR0206,
CheckCode::PLR0402,
CheckCode::PLR1701,
CheckCode::PLR1722,
CheckCode::PLW0120,
CheckCode::PLW0602,
CheckCode::A001,
CheckCode::A002,
CheckCode::A003,
CheckCode::B002,
CheckCode::B003,
CheckCode::B004,
CheckCode::B005,
CheckCode::B006,
CheckCode::B007,
CheckCode::B008,
CheckCode::B009,
CheckCode::B010,
CheckCode::B011,
CheckCode::B012,
CheckCode::B013,
CheckCode::B014,
CheckCode::B015,
CheckCode::B016,
CheckCode::B017,
CheckCode::B018,
CheckCode::B019,
CheckCode::B020,
CheckCode::B021,
CheckCode::B022,
CheckCode::B023,
CheckCode::B024,
CheckCode::B025,
CheckCode::B026,
CheckCode::B027,
CheckCode::B904,
CheckCode::B905,
CheckCode::BLE001,
CheckCode::C400,
CheckCode::C401,
CheckCode::C402,
CheckCode::C403,
CheckCode::C404,
CheckCode::C405,
CheckCode::C406,
CheckCode::C408,
CheckCode::C409,
CheckCode::C410,
CheckCode::C411,
CheckCode::C413,
CheckCode::C414,
CheckCode::C415,
CheckCode::C416,
CheckCode::C417,
CheckCode::T100,
CheckCode::C901,
CheckCode::TID252,
CheckCode::RET501,
CheckCode::RET502,
CheckCode::RET503,
CheckCode::RET504,
CheckCode::RET505,
CheckCode::RET506,
CheckCode::RET507,
CheckCode::RET508,
CheckCode::T201,
CheckCode::T203,
CheckCode::Q000,
CheckCode::Q001,
CheckCode::Q002,
CheckCode::Q003,
CheckCode::ANN001,
CheckCode::ANN002,
CheckCode::ANN003,
CheckCode::ANN101,
CheckCode::ANN102,
CheckCode::ANN201,
CheckCode::ANN202,
CheckCode::ANN204,
CheckCode::ANN205,
CheckCode::ANN206,
CheckCode::ANN401,
CheckCode::YTT101,
CheckCode::YTT102,
CheckCode::YTT103,
CheckCode::YTT201,
CheckCode::YTT202,
CheckCode::YTT203,
CheckCode::YTT204,
CheckCode::YTT301,
CheckCode::YTT302,
CheckCode::YTT303,
CheckCode::SIM118,
CheckCode::UP001,
CheckCode::UP003,
CheckCode::UP004,
CheckCode::UP005,
CheckCode::UP006,
CheckCode::UP007,
CheckCode::UP008,
CheckCode::UP009,
CheckCode::UP010,
CheckCode::UP011,
CheckCode::UP012,
CheckCode::UP013,
CheckCode::UP014,
CheckCode::UP015,
CheckCode::UP016,
CheckCode::UP017,
CheckCode::UP018,
CheckCode::UP019,
CheckCode::UP020,
CheckCode::UP021,
CheckCode::UP022,
CheckCode::UP023,
CheckCode::D100,
CheckCode::D101,
CheckCode::D102,
CheckCode::D103,
CheckCode::D104,
CheckCode::D105,
CheckCode::D106,
CheckCode::D107,
CheckCode::D200,
CheckCode::D201,
CheckCode::D202,
CheckCode::D203,
CheckCode::D204,
CheckCode::D205,
CheckCode::D206,
CheckCode::D207,
CheckCode::D208,
CheckCode::D209,
CheckCode::D210,
CheckCode::D211,
CheckCode::D212,
CheckCode::D213,
CheckCode::D214,
CheckCode::D215,
CheckCode::D300,
CheckCode::D301,
CheckCode::D400,
CheckCode::D402,
CheckCode::D403,
CheckCode::D404,
CheckCode::D405,
CheckCode::D406,
CheckCode::D407,
CheckCode::D408,
CheckCode::D409,
CheckCode::D410,
CheckCode::D411,
CheckCode::D412,
CheckCode::D413,
CheckCode::D414,
CheckCode::D415,
CheckCode::D416,
CheckCode::D417,
CheckCode::D418,
CheckCode::D419,
CheckCode::N801,
CheckCode::N802,
CheckCode::N803,
CheckCode::N804,
CheckCode::N805,
CheckCode::N806,
CheckCode::N807,
CheckCode::N811,
CheckCode::N812,
CheckCode::N813,
CheckCode::N814,
CheckCode::N815,
CheckCode::N816,
CheckCode::N817,
CheckCode::N818,
CheckCode::I001,
CheckCode::ERA001,
CheckCode::S101,
CheckCode::S102,
CheckCode::S104,
CheckCode::S105,
CheckCode::S106,
CheckCode::S107,
CheckCode::FBT001,
CheckCode::FBT002,
CheckCode::FBT003,
CheckCode::ARG001,
CheckCode::ARG002,
CheckCode::ARG003,
CheckCode::ARG004,
CheckCode::ARG005,
CheckCode::ICN001,
CheckCode::DTZ001,
CheckCode::DTZ002,
CheckCode::DTZ003,
CheckCode::DTZ004,
CheckCode::DTZ005,
CheckCode::DTZ006,
CheckCode::DTZ007,
CheckCode::DTZ011,
CheckCode::DTZ012,
CheckCode::RUF001,
CheckCode::RUF002,
CheckCode::RUF003,
CheckCode::RUF004,
CheckCode::RUF100,
CheckCode::PGH001,
CheckCode::PGH002,
CheckCode::PGH003,
CheckCode::PD002,
CheckCode::PD003,
CheckCode::PD004,
CheckCode::PD007,
CheckCode::PD008,
CheckCode::PD009,
CheckCode::PD010,
CheckCode::PD011,
CheckCode::PD012,
CheckCode::PD013,
CheckCode::PD015,
CheckCode::PD901,
CheckCode::EM101,
CheckCode::EM102,
CheckCode::EM103,
],
CheckCodePrefix::ANN => vec![
CheckCode::ANN001,
CheckCode::ANN002,
@@ -1046,6 +1381,7 @@ impl CheckCodePrefix {
CheckCodePrefix::DTZ011 => vec![CheckCode::DTZ011],
CheckCodePrefix::DTZ012 => vec![CheckCode::DTZ012],
CheckCodePrefix::E => vec![
CheckCode::E401,
CheckCode::E402,
CheckCode::E501,
CheckCode::E711,
@@ -1061,8 +1397,9 @@ impl CheckCodePrefix {
CheckCode::E902,
CheckCode::E999,
],
CheckCodePrefix::E4 => vec![CheckCode::E402],
CheckCodePrefix::E40 => vec![CheckCode::E402],
CheckCodePrefix::E4 => vec![CheckCode::E401, CheckCode::E402],
CheckCodePrefix::E40 => vec![CheckCode::E401, CheckCode::E402],
CheckCodePrefix::E401 => vec![CheckCode::E401],
CheckCodePrefix::E402 => vec![CheckCode::E402],
CheckCodePrefix::E5 => vec![CheckCode::E501],
CheckCodePrefix::E50 => vec![CheckCode::E501],
@@ -1343,6 +1680,60 @@ impl CheckCodePrefix {
);
vec![CheckCode::TID252]
}
CheckCodePrefix::IC => {
one_time_warning!(
"{}{} {}",
"warning".yellow().bold(),
":".bold(),
"`IC` has been remapped to `ICN`".bold()
);
vec![CheckCode::ICN001]
}
CheckCodePrefix::IC0 => {
one_time_warning!(
"{}{} {}",
"warning".yellow().bold(),
":".bold(),
"`IC0` has been remapped to `ICN0`".bold()
);
vec![CheckCode::ICN001]
}
CheckCodePrefix::IC001 => {
one_time_warning!(
"{}{} {}",
"warning".yellow().bold(),
":".bold(),
"`IC001` has been remapped to `ICN001`".bold()
);
vec![CheckCode::ICN001]
}
CheckCodePrefix::IC002 => {
one_time_warning!(
"{}{} {}",
"warning".yellow().bold(),
":".bold(),
"`IC002` has been remapped to `ICN001`".bold()
);
vec![CheckCode::ICN001]
}
CheckCodePrefix::IC003 => {
one_time_warning!(
"{}{} {}",
"warning".yellow().bold(),
":".bold(),
"`IC003` has been remapped to `ICN001`".bold()
);
vec![CheckCode::ICN001]
}
CheckCodePrefix::IC004 => {
one_time_warning!(
"{}{} {}",
"warning".yellow().bold(),
":".bold(),
"`IC004` has been remapped to `ICN001`".bold()
);
vec![CheckCode::ICN001]
}
CheckCodePrefix::ICN => vec![CheckCode::ICN001],
CheckCodePrefix::ICN0 => vec![CheckCode::ICN001],
CheckCodePrefix::ICN00 => vec![CheckCode::ICN001],
@@ -1764,6 +2155,132 @@ impl CheckCodePrefix {
CheckCodePrefix::Q001 => vec![CheckCode::Q001],
CheckCodePrefix::Q002 => vec![CheckCode::Q002],
CheckCodePrefix::Q003 => vec![CheckCode::Q003],
CheckCodePrefix::R => {
one_time_warning!(
"{}{} {}",
"warning".yellow().bold(),
":".bold(),
"`R` has been remapped to `RET`".bold()
);
vec![
CheckCode::RET501,
CheckCode::RET502,
CheckCode::RET503,
CheckCode::RET504,
CheckCode::RET505,
CheckCode::RET506,
CheckCode::RET507,
CheckCode::RET508,
]
}
CheckCodePrefix::R5 => {
one_time_warning!(
"{}{} {}",
"warning".yellow().bold(),
":".bold(),
"`R5` has been remapped to `RET5`".bold()
);
vec![
CheckCode::RET501,
CheckCode::RET502,
CheckCode::RET503,
CheckCode::RET504,
CheckCode::RET505,
CheckCode::RET506,
CheckCode::RET507,
CheckCode::RET508,
]
}
CheckCodePrefix::R50 => {
one_time_warning!(
"{}{} {}",
"warning".yellow().bold(),
":".bold(),
"`R50` has been remapped to `RET50`".bold()
);
vec![
CheckCode::RET501,
CheckCode::RET502,
CheckCode::RET503,
CheckCode::RET504,
CheckCode::RET505,
CheckCode::RET506,
CheckCode::RET507,
CheckCode::RET508,
]
}
CheckCodePrefix::R501 => {
one_time_warning!(
"{}{} {}",
"warning".yellow().bold(),
":".bold(),
"`R501` has been remapped to `RET501`".bold()
);
vec![CheckCode::RET501]
}
CheckCodePrefix::R502 => {
one_time_warning!(
"{}{} {}",
"warning".yellow().bold(),
":".bold(),
"`R502` has been remapped to `RET502`".bold()
);
vec![CheckCode::RET502]
}
CheckCodePrefix::R503 => {
one_time_warning!(
"{}{} {}",
"warning".yellow().bold(),
":".bold(),
"`R503` has been remapped to `RET503`".bold()
);
vec![CheckCode::RET503]
}
CheckCodePrefix::R504 => {
one_time_warning!(
"{}{} {}",
"warning".yellow().bold(),
":".bold(),
"`R504` has been remapped to `RET504`".bold()
);
vec![CheckCode::RET504]
}
CheckCodePrefix::R505 => {
one_time_warning!(
"{}{} {}",
"warning".yellow().bold(),
":".bold(),
"`R505` has been remapped to `RET505`".bold()
);
vec![CheckCode::RET505]
}
CheckCodePrefix::R506 => {
one_time_warning!(
"{}{} {}",
"warning".yellow().bold(),
":".bold(),
"`R506` has been remapped to `RET506`".bold()
);
vec![CheckCode::RET506]
}
CheckCodePrefix::R507 => {
one_time_warning!(
"{}{} {}",
"warning".yellow().bold(),
":".bold(),
"`R507` has been remapped to `RET507`".bold()
);
vec![CheckCode::RET507]
}
CheckCodePrefix::R508 => {
one_time_warning!(
"{}{} {}",
"warning".yellow().bold(),
":".bold(),
"`R508` has been remapped to `RET508`".bold()
);
vec![CheckCode::RET508]
}
CheckCodePrefix::RET => vec![
CheckCode::RET501,
CheckCode::RET502,
@@ -1806,13 +2323,25 @@ impl CheckCodePrefix {
CheckCode::RUF001,
CheckCode::RUF002,
CheckCode::RUF003,
CheckCode::RUF004,
CheckCode::RUF100,
],
CheckCodePrefix::RUF0 => vec![CheckCode::RUF001, CheckCode::RUF002, CheckCode::RUF003],
CheckCodePrefix::RUF00 => vec![CheckCode::RUF001, CheckCode::RUF002, CheckCode::RUF003],
CheckCodePrefix::RUF0 => vec![
CheckCode::RUF001,
CheckCode::RUF002,
CheckCode::RUF003,
CheckCode::RUF004,
],
CheckCodePrefix::RUF00 => vec![
CheckCode::RUF001,
CheckCode::RUF002,
CheckCode::RUF003,
CheckCode::RUF004,
],
CheckCodePrefix::RUF001 => vec![CheckCode::RUF001],
CheckCodePrefix::RUF002 => vec![CheckCode::RUF002],
CheckCodePrefix::RUF003 => vec![CheckCode::RUF003],
CheckCodePrefix::RUF004 => vec![CheckCode::RUF004],
CheckCodePrefix::RUF1 => vec![CheckCode::RUF100],
CheckCodePrefix::RUF10 => vec![CheckCode::RUF100],
CheckCodePrefix::RUF100 => vec![CheckCode::RUF100],
@@ -1885,6 +2414,13 @@ impl CheckCodePrefix {
CheckCode::UP014,
CheckCode::UP015,
CheckCode::UP016,
CheckCode::UP017,
CheckCode::UP018,
CheckCode::UP019,
CheckCode::UP020,
CheckCode::UP021,
CheckCode::UP022,
CheckCode::UP023,
]
}
CheckCodePrefix::U0 => {
@@ -1910,6 +2446,13 @@ impl CheckCodePrefix {
CheckCode::UP014,
CheckCode::UP015,
CheckCode::UP016,
CheckCode::UP017,
CheckCode::UP018,
CheckCode::UP019,
CheckCode::UP020,
CheckCode::UP021,
CheckCode::UP022,
CheckCode::UP023,
]
}
CheckCodePrefix::U00 => {
@@ -2017,6 +2560,9 @@ impl CheckCodePrefix {
CheckCode::UP014,
CheckCode::UP015,
CheckCode::UP016,
CheckCode::UP017,
CheckCode::UP018,
CheckCode::UP019,
]
}
CheckCodePrefix::U010 => {
@@ -2082,6 +2628,24 @@ impl CheckCodePrefix {
);
vec![CheckCode::UP016]
}
CheckCodePrefix::U017 => {
one_time_warning!(
"{}{} {}",
"warning".yellow().bold(),
":".bold(),
"`U017` has been remapped to `UP017`".bold()
);
vec![CheckCode::UP017]
}
CheckCodePrefix::U019 => {
one_time_warning!(
"{}{} {}",
"warning".yellow().bold(),
":".bold(),
"`U019` has been remapped to `UP019`".bold()
);
vec![CheckCode::UP019]
}
CheckCodePrefix::UP => vec![
CheckCode::UP001,
CheckCode::UP003,
@@ -2098,6 +2662,13 @@ impl CheckCodePrefix {
CheckCode::UP014,
CheckCode::UP015,
CheckCode::UP016,
CheckCode::UP017,
CheckCode::UP018,
CheckCode::UP019,
CheckCode::UP020,
CheckCode::UP021,
CheckCode::UP022,
CheckCode::UP023,
],
CheckCodePrefix::UP0 => vec![
CheckCode::UP001,
@@ -2115,6 +2686,13 @@ impl CheckCodePrefix {
CheckCode::UP014,
CheckCode::UP015,
CheckCode::UP016,
CheckCode::UP017,
CheckCode::UP018,
CheckCode::UP019,
CheckCode::UP020,
CheckCode::UP021,
CheckCode::UP022,
CheckCode::UP023,
],
CheckCodePrefix::UP00 => vec![
CheckCode::UP001,
@@ -2142,6 +2720,9 @@ impl CheckCodePrefix {
CheckCode::UP014,
CheckCode::UP015,
CheckCode::UP016,
CheckCode::UP017,
CheckCode::UP018,
CheckCode::UP019,
],
CheckCodePrefix::UP010 => vec![CheckCode::UP010],
CheckCodePrefix::UP011 => vec![CheckCode::UP011],
@@ -2150,6 +2731,19 @@ impl CheckCodePrefix {
CheckCodePrefix::UP014 => vec![CheckCode::UP014],
CheckCodePrefix::UP015 => vec![CheckCode::UP015],
CheckCodePrefix::UP016 => vec![CheckCode::UP016],
CheckCodePrefix::UP017 => vec![CheckCode::UP017],
CheckCodePrefix::UP018 => vec![CheckCode::UP018],
CheckCodePrefix::UP019 => vec![CheckCode::UP019],
CheckCodePrefix::UP02 => vec![
CheckCode::UP020,
CheckCode::UP021,
CheckCode::UP022,
CheckCode::UP023,
],
CheckCodePrefix::UP020 => vec![CheckCode::UP020],
CheckCodePrefix::UP021 => vec![CheckCode::UP021],
CheckCodePrefix::UP022 => vec![CheckCode::UP022],
CheckCodePrefix::UP023 => vec![CheckCode::UP023],
CheckCodePrefix::W => vec![CheckCode::W292, CheckCode::W605],
CheckCodePrefix::W2 => vec![CheckCode::W292],
CheckCodePrefix::W29 => vec![CheckCode::W292],
@@ -2209,6 +2803,7 @@ impl CheckCodePrefix {
CheckCodePrefix::A001 => SuffixLength::Three,
CheckCodePrefix::A002 => SuffixLength::Three,
CheckCodePrefix::A003 => SuffixLength::Three,
CheckCodePrefix::ALL => SuffixLength::None,
CheckCodePrefix::ANN => SuffixLength::Zero,
CheckCodePrefix::ANN0 => SuffixLength::One,
CheckCodePrefix::ANN00 => SuffixLength::Two,
@@ -2371,6 +2966,7 @@ impl CheckCodePrefix {
CheckCodePrefix::E => SuffixLength::Zero,
CheckCodePrefix::E4 => SuffixLength::One,
CheckCodePrefix::E40 => SuffixLength::Two,
CheckCodePrefix::E401 => SuffixLength::Three,
CheckCodePrefix::E402 => SuffixLength::Three,
CheckCodePrefix::E5 => SuffixLength::One,
CheckCodePrefix::E50 => SuffixLength::Two,
@@ -2483,6 +3079,12 @@ impl CheckCodePrefix {
CheckCodePrefix::I2 => SuffixLength::One,
CheckCodePrefix::I25 => SuffixLength::Two,
CheckCodePrefix::I252 => SuffixLength::Three,
CheckCodePrefix::IC => SuffixLength::Zero,
CheckCodePrefix::IC0 => SuffixLength::One,
CheckCodePrefix::IC001 => SuffixLength::Three,
CheckCodePrefix::IC002 => SuffixLength::Three,
CheckCodePrefix::IC003 => SuffixLength::Three,
CheckCodePrefix::IC004 => SuffixLength::Three,
CheckCodePrefix::ICN => SuffixLength::Zero,
CheckCodePrefix::ICN0 => SuffixLength::One,
CheckCodePrefix::ICN00 => SuffixLength::Two,
@@ -2602,6 +3204,17 @@ impl CheckCodePrefix {
CheckCodePrefix::Q001 => SuffixLength::Three,
CheckCodePrefix::Q002 => SuffixLength::Three,
CheckCodePrefix::Q003 => SuffixLength::Three,
CheckCodePrefix::R => SuffixLength::Zero,
CheckCodePrefix::R5 => SuffixLength::One,
CheckCodePrefix::R50 => SuffixLength::Two,
CheckCodePrefix::R501 => SuffixLength::Three,
CheckCodePrefix::R502 => SuffixLength::Three,
CheckCodePrefix::R503 => SuffixLength::Three,
CheckCodePrefix::R504 => SuffixLength::Three,
CheckCodePrefix::R505 => SuffixLength::Three,
CheckCodePrefix::R506 => SuffixLength::Three,
CheckCodePrefix::R507 => SuffixLength::Three,
CheckCodePrefix::R508 => SuffixLength::Three,
CheckCodePrefix::RET => SuffixLength::Zero,
CheckCodePrefix::RET5 => SuffixLength::One,
CheckCodePrefix::RET50 => SuffixLength::Two,
@@ -2619,6 +3232,7 @@ impl CheckCodePrefix {
CheckCodePrefix::RUF001 => SuffixLength::Three,
CheckCodePrefix::RUF002 => SuffixLength::Three,
CheckCodePrefix::RUF003 => SuffixLength::Three,
CheckCodePrefix::RUF004 => SuffixLength::Three,
CheckCodePrefix::RUF1 => SuffixLength::One,
CheckCodePrefix::RUF10 => SuffixLength::Two,
CheckCodePrefix::RUF100 => SuffixLength::Three,
@@ -2666,6 +3280,8 @@ impl CheckCodePrefix {
CheckCodePrefix::U014 => SuffixLength::Three,
CheckCodePrefix::U015 => SuffixLength::Three,
CheckCodePrefix::U016 => SuffixLength::Three,
CheckCodePrefix::U017 => SuffixLength::Three,
CheckCodePrefix::U019 => SuffixLength::Three,
CheckCodePrefix::UP => SuffixLength::Zero,
CheckCodePrefix::UP0 => SuffixLength::One,
CheckCodePrefix::UP00 => SuffixLength::Two,
@@ -2685,6 +3301,14 @@ impl CheckCodePrefix {
CheckCodePrefix::UP014 => SuffixLength::Three,
CheckCodePrefix::UP015 => SuffixLength::Three,
CheckCodePrefix::UP016 => SuffixLength::Three,
CheckCodePrefix::UP017 => SuffixLength::Three,
CheckCodePrefix::UP018 => SuffixLength::Three,
CheckCodePrefix::UP019 => SuffixLength::Three,
CheckCodePrefix::UP02 => SuffixLength::Two,
CheckCodePrefix::UP020 => SuffixLength::Three,
CheckCodePrefix::UP021 => SuffixLength::Three,
CheckCodePrefix::UP022 => SuffixLength::Three,
CheckCodePrefix::UP023 => SuffixLength::Three,
CheckCodePrefix::W => SuffixLength::Zero,
CheckCodePrefix::W2 => SuffixLength::One,
CheckCodePrefix::W29 => SuffixLength::Two,
@@ -2715,6 +3339,7 @@ impl CheckCodePrefix {
pub const CATEGORIES: &[CheckCodePrefix] = &[
CheckCodePrefix::A,
CheckCodePrefix::ALL,
CheckCodePrefix::ANN,
CheckCodePrefix::ARG,
CheckCodePrefix::B,

View File

@@ -19,7 +19,8 @@ use crate::settings::types::{
pub struct Cli {
#[arg(required_unless_present_any = ["explain", "generate_shell_completion"])]
pub files: Vec<PathBuf>,
/// Path to the `pyproject.toml` file to use for configuration.
/// Path to the `pyproject.toml` or `ruff.toml` file to use for
/// configuration.
#[arg(long)]
pub config: Option<PathBuf>,
/// Enable verbose logging.
@@ -43,6 +44,16 @@ pub struct Cli {
fix: bool,
#[clap(long, overrides_with("fix"), hide = true)]
no_fix: bool,
/// Fix any fixable lint errors, but don't report on leftover violations.
/// Implies `--fix`.
#[arg(long, overrides_with("no_fix_only"))]
fix_only: bool,
#[clap(long, overrides_with("fix_only"), hide = true)]
no_fix_only: bool,
/// Avoid writing any fixed files back; instead, output a diff for each
/// changed file to stdout.
#[arg(long)]
pub diff: bool,
/// Disable cache reads.
#[arg(short, long)]
pub no_cache: bool,
@@ -133,6 +144,9 @@ pub struct Cli {
/// Generate shell completion
#[arg(long, hide = true, value_name = "SHELL")]
pub generate_shell_completion: Option<clap_complete_command::Shell>,
/// Path to the cache directory.
#[arg(long)]
pub cache_dir: Option<PathBuf>,
}
impl Cli {
@@ -144,6 +158,7 @@ impl Cli {
add_noqa: self.add_noqa,
autoformat: self.autoformat,
config: self.config,
diff: self.diff,
exit_zero: self.exit_zero,
explain: self.explain,
files: self.files,
@@ -178,8 +193,10 @@ impl Cli {
unfixable: self.unfixable,
// TODO(charlie): Included in `pyproject.toml`, but not inherited.
fix: resolve_bool_arg(self.fix, self.no_fix),
fix_only: resolve_bool_arg(self.fix_only, self.no_fix_only),
format: self.format,
force_exclude: resolve_bool_arg(self.force_exclude, self.no_force_exclude),
cache_dir: self.cache_dir,
},
)
}
@@ -201,6 +218,7 @@ pub struct Arguments {
pub add_noqa: bool,
pub autoformat: bool,
pub config: Option<PathBuf>,
pub diff: bool,
pub exit_zero: bool,
pub explain: Option<CheckCode>,
pub files: Vec<PathBuf>,
@@ -236,8 +254,10 @@ pub struct Overrides {
pub unfixable: Option<Vec<CheckCodePrefix>>,
// TODO(charlie): Captured in pyproject.toml as a default, but not part of `Settings`.
pub fix: Option<bool>,
pub fix_only: Option<bool>,
pub format: Option<SerializationFormat>,
pub force_exclude: Option<bool>,
pub cache_dir: Option<PathBuf>,
}
/// Map the CLI settings to a `LogLevel`.

View File

@@ -20,7 +20,7 @@ use crate::message::Message;
use crate::resolver::{FileDiscovery, PyprojectDiscovery};
use crate::settings::flags;
use crate::settings::types::SerializationFormat;
use crate::{packages, resolver};
use crate::{cache, packages, resolver};
/// Run the linter over a collection of files.
pub fn run(
@@ -38,6 +38,33 @@ pub fn run(
let duration = start.elapsed();
debug!("Identified files to lint in: {:?}", duration);
// Validate the `Settings` and return any errors.
resolver.validate(pyproject_strategy)?;
// Initialize the cache.
if matches!(cache, flags::Cache::Enabled) {
match &pyproject_strategy {
PyprojectDiscovery::Fixed(settings) => {
if let Err(e) = cache::init(&settings.cache_dir) {
error!(
"Failed to initialize cache at {}: {e:?}",
settings.cache_dir.to_string_lossy()
);
}
}
PyprojectDiscovery::Hierarchical(default) => {
for settings in std::iter::once(default).chain(resolver.iter()) {
if let Err(e) = cache::init(&settings.cache_dir) {
error!(
"Failed to initialize cache at {}: {e:?}",
settings.cache_dir.to_string_lossy()
);
}
}
}
}
};
// Discover the package root for each Python file.
let package_roots = packages::detect_package_roots(
&paths
@@ -114,16 +141,26 @@ fn read_from_stdin() -> Result<String> {
/// Run the linter over a single file, read from `stdin`.
pub fn run_stdin(
strategy: &PyprojectDiscovery,
filename: &Path,
filename: Option<&Path>,
pyproject_strategy: &PyprojectDiscovery,
file_strategy: &FileDiscovery,
overrides: &Overrides,
autofix: fixer::Mode,
) -> Result<Diagnostics> {
let stdin = read_from_stdin()?;
let settings = match strategy {
if let Some(filename) = filename {
if !resolver::python_file_at_path(filename, pyproject_strategy, file_strategy, overrides)? {
return Ok(Diagnostics::default());
}
}
let settings = match pyproject_strategy {
PyprojectDiscovery::Fixed(settings) => settings,
PyprojectDiscovery::Hierarchical(settings) => settings,
};
let mut diagnostics = lint_stdin(filename, &stdin, settings, autofix)?;
let package_root = filename
.and_then(Path::parent)
.and_then(packages::detect_package_root);
let stdin = read_from_stdin()?;
let mut diagnostics = lint_stdin(filename, package_root, &stdin, settings, autofix)?;
diagnostics.messages.sort_unstable();
Ok(diagnostics)
}
@@ -142,6 +179,9 @@ pub fn add_noqa(
let duration = start.elapsed();
debug!("Identified files to lint in: {:?}", duration);
// Validate the `Settings` and return any errors.
resolver.validate(pyproject_strategy)?;
let start = Instant::now();
let modifications: usize = par_iter(&paths)
.flatten()
@@ -178,6 +218,9 @@ pub fn autoformat(
let duration = start.elapsed();
debug!("Identified files to lint in: {:?}", duration);
// Validate the `Settings` and return any errors.
resolver.validate(pyproject_strategy)?;
let start = Instant::now();
let modifications = par_iter(&paths)
.flatten()
@@ -211,6 +254,9 @@ pub fn show_settings(
let (paths, resolver) =
resolver::python_files_in_path(files, pyproject_strategy, file_strategy, overrides)?;
// Validate the `Settings` and return any errors.
resolver.validate(pyproject_strategy)?;
// Print the list of files.
let Some(entry) = paths
.iter()
@@ -234,9 +280,12 @@ pub fn show_files(
overrides: &Overrides,
) -> Result<()> {
// Collect all files in the hierarchy.
let (paths, _resolver) =
let (paths, resolver) =
resolver::python_files_in_path(files, pyproject_strategy, file_strategy, overrides)?;
// Validate the `Settings` and return any errors.
resolver.validate(pyproject_strategy)?;
// Print the list of files.
for entry in paths
.iter()
@@ -283,6 +332,9 @@ pub fn explain(code: &CheckCode, format: &SerializationFormat) -> Result<()> {
SerializationFormat::Github => {
bail!("`--explain` does not support GitHub format")
}
SerializationFormat::Gitlab => {
bail!("`--explain` does not support GitLab format")
}
};
Ok(())
}

View File

@@ -3,7 +3,6 @@ use rustpython_ast::Stmt;
use rustpython_parser::lexer;
use rustpython_parser::lexer::Tok;
use crate::ast::helpers;
use crate::ast::types::Range;
use crate::autofix::Fix;
use crate::source_code_locator::SourceCodeLocator;
@@ -17,13 +16,10 @@ pub fn add_return_none_annotation(locator: &SourceCodeLocator, stmt: &Stmt) -> R
let mut seen_lpar = false;
let mut seen_rpar = false;
let mut count: usize = 0;
for (start, tok, ..) in lexer::make_tokenizer(&contents).flatten() {
for (start, tok, ..) in lexer::make_tokenizer_located(&contents, range.location).flatten() {
if seen_lpar && seen_rpar {
if matches!(tok, Tok::Colon) {
return Ok(Fix::insertion(
" -> None".to_string(),
helpers::to_absolute(start, range.location),
));
return Ok(Fix::insertion(" -> None".to_string(), start));
}
}

View File

@@ -1,51 +1,53 @@
//! Settings for the `flake-annotations` plugin.
use ruff_macros::ConfigurationOptions;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Default, ConfigurationOptions)]
#[serde(deny_unknown_fields, rename_all = "kebab-case")]
#[derive(
Debug, PartialEq, Eq, Serialize, Deserialize, Default, ConfigurationOptions, JsonSchema,
)]
#[serde(
deny_unknown_fields,
rename_all = "kebab-case",
rename = "Flake8AnnotationsOptions"
)]
pub struct Options {
#[option(
doc = r#"
Whether to allow the omission of a return type hint for `__init__` if at least one
argument is annotated.
"#,
default = "false",
value_type = "bool",
example = "mypy-init-return = true"
)]
/// Whether to allow the omission of a return type hint for `__init__` if at
/// least one argument is annotated.
pub mypy_init_return: Option<bool>,
#[option(
doc = r#"
Whether to suppress `ANN000`-level errors for arguments matching the "dummy" variable
regex (like `_`).
"#,
default = "false",
value_type = "bool",
example = "suppress-dummy-args = true"
)]
/// Whether to suppress `ANN000`-level errors for arguments matching the
/// "dummy" variable regex (like `_`).
pub suppress_dummy_args: Option<bool>,
#[option(
doc = r#"
Whether to suppress `ANN200`-level errors for functions that meet either of the
following criteria:
- Contain no `return` statement.
- Explicit `return` statement(s) all return `None` (explicitly or implicitly).
"#,
default = "false",
value_type = "bool",
example = "suppress-none-returning = true"
)]
/// Whether to suppress `ANN200`-level errors for functions that meet either
/// of the following criteria:
///
/// - Contain no `return` statement.
/// - Explicit `return` statement(s) all return `None` (explicitly or
/// implicitly).
pub suppress_none_returning: Option<bool>,
#[option(
doc = "Whether to suppress `ANN401` for dynamically typed `*args` and `**kwargs` \
arguments.",
default = "false",
value_type = "bool",
example = "allow-star-arg-any = true"
)]
/// Whether to suppress `ANN401` for dynamically typed `*args` and
/// `**kwargs` arguments.
pub allow_star_arg_any: Option<bool>,
}

View File

@@ -5,16 +5,35 @@ use crate::ast::types::Range;
use crate::checkers::ast::Checker;
use crate::checks::{Check, CheckKind};
const FUNC_NAME_ALLOWLIST: &[&str] = &["get", "setdefault", "pop", "fromkeys"];
const FUNC_NAME_ALLOWLIST: &[&str] = &[
"assertEqual",
"assertEquals",
"assertNotEqual",
"assertNotEquals",
"failIfEqual",
"failUnlessEqual",
"fromkeys",
"get",
"getattr",
"index",
"pop",
"setattr",
"setdefault",
];
/// Returns `true` if an argument is allowed to use a boolean trap. To return
/// `true`, the function name must be explicitly allowed, and the argument must
/// be either the first or second argument in the call.
fn allow_boolean_trap(func: &Expr) -> bool {
let ExprKind::Attribute { attr, .. } = &func.node else {
return false;
};
FUNC_NAME_ALLOWLIST.contains(&attr.as_ref())
if let ExprKind::Attribute { attr, .. } = &func.node {
return FUNC_NAME_ALLOWLIST.contains(&attr.as_ref());
}
if let ExprKind::Name { id, .. } = &func.node {
return FUNC_NAME_ALLOWLIST.contains(&id.as_ref());
}
false
}
fn is_boolean_arg(arg: &Expr) -> bool {
@@ -79,8 +98,8 @@ pub fn check_boolean_positional_value_in_function_call(
args: &[Expr],
func: &Expr,
) {
for (index, arg) in args.iter().enumerate() {
if index < 2 && allow_boolean_trap(func) {
for arg in args {
if allow_boolean_trap(func) {
continue;
}
add_if_boolean(

View File

@@ -4,7 +4,7 @@ use crate::ast::types::Range;
use crate::autofix::Fix;
use crate::checkers::ast::Checker;
use crate::checks::{Check, CheckKind};
use crate::code_gen::SourceGenerator;
use crate::source_code_generator::SourceCodeGenerator;
fn assertion_error(msg: Option<&Expr>) -> Stmt {
Stmt::new(
@@ -47,7 +47,8 @@ pub fn assert_false(checker: &mut Checker, stmt: &Stmt, test: &Expr, msg: Option
let mut check = Check::new(CheckKind::DoNotAssertFalse, Range::from_located(test));
if checker.patch(check.kind.code()) {
let mut generator = SourceGenerator::new();
let mut generator =
SourceCodeGenerator::new(checker.style.indentation(), checker.style.quote());
generator.unparse_stmt(&assertion_error(msg));
if let Ok(content) = generator.generate() {
check.amend(Fix::replacement(

View File

@@ -1,15 +1,13 @@
use itertools::Itertools;
use rustc_hash::FxHashSet;
use rustpython_ast::{
Excepthandler, ExcepthandlerKind, Expr, ExprContext, ExprKind, Location, Stmt,
};
use rustc_hash::{FxHashMap, FxHashSet};
use rustpython_ast::{Excepthandler, ExcepthandlerKind, Expr, ExprContext, ExprKind, Location};
use crate::ast::helpers;
use crate::ast::types::Range;
use crate::autofix::Fix;
use crate::checkers::ast::Checker;
use crate::checks::{Check, CheckCode, CheckKind};
use crate::code_gen::SourceGenerator;
use crate::source_code_generator::SourceCodeGenerator;
fn type_pattern(elts: Vec<&Expr>) -> Expr {
Expr::new(
@@ -26,17 +24,17 @@ fn duplicate_handler_exceptions<'a>(
checker: &mut Checker,
expr: &'a Expr,
elts: &'a [Expr],
) -> FxHashSet<Vec<&'a str>> {
let mut seen: FxHashSet<Vec<&str>> = FxHashSet::default();
) -> FxHashMap<Vec<&'a str>, &'a Expr> {
let mut seen: FxHashMap<Vec<&str>, &Expr> = FxHashMap::default();
let mut duplicates: FxHashSet<Vec<&str>> = FxHashSet::default();
let mut unique_elts: Vec<&Expr> = Vec::default();
for type_ in elts {
let call_path = helpers::collect_call_paths(type_);
if !call_path.is_empty() {
if seen.contains(&call_path) {
if seen.contains_key(&call_path) {
duplicates.insert(call_path);
} else {
seen.insert(call_path);
seen.entry(call_path).or_insert(type_);
unique_elts.push(type_);
}
}
@@ -56,7 +54,8 @@ fn duplicate_handler_exceptions<'a>(
Range::from_located(expr),
);
if checker.patch(check.kind.code()) {
let mut generator = SourceGenerator::new();
let mut generator =
SourceCodeGenerator::new(checker.style.indentation(), checker.style.quote());
if unique_elts.len() == 1 {
generator.unparse_expr(unique_elts[0], 0);
} else {
@@ -77,9 +76,9 @@ fn duplicate_handler_exceptions<'a>(
seen
}
pub fn duplicate_exceptions(checker: &mut Checker, stmt: &Stmt, handlers: &[Excepthandler]) {
pub fn duplicate_exceptions(checker: &mut Checker, handlers: &[Excepthandler]) {
let mut seen: FxHashSet<Vec<&str>> = FxHashSet::default();
let mut duplicates: FxHashSet<Vec<&str>> = FxHashSet::default();
let mut duplicates: FxHashMap<Vec<&str>, Vec<&Expr>> = FxHashMap::default();
for handler in handlers {
let ExcepthandlerKind::ExceptHandler { type_: Some(type_), .. } = &handler.node else {
continue;
@@ -89,16 +88,16 @@ pub fn duplicate_exceptions(checker: &mut Checker, stmt: &Stmt, handlers: &[Exce
let call_path = helpers::collect_call_paths(type_);
if !call_path.is_empty() {
if seen.contains(&call_path) {
duplicates.insert(call_path);
duplicates.entry(call_path).or_default().push(type_);
} else {
seen.insert(call_path);
}
}
}
ExprKind::Tuple { elts, .. } => {
for name in duplicate_handler_exceptions(checker, type_, elts) {
for (name, expr) in duplicate_handler_exceptions(checker, type_, elts) {
if seen.contains(&name) {
duplicates.insert(name);
duplicates.entry(name).or_default().push(expr);
} else {
seen.insert(name);
}
@@ -109,11 +108,13 @@ pub fn duplicate_exceptions(checker: &mut Checker, stmt: &Stmt, handlers: &[Exce
}
if checker.settings.enabled.contains(&CheckCode::B025) {
for duplicate in duplicates.into_iter().sorted() {
checker.add_check(Check::new(
CheckKind::DuplicateTryBlockException(duplicate.join(".")),
Range::from_located(stmt),
));
for (name, exprs) in duplicates {
for expr in exprs {
checker.add_check(Check::new(
CheckKind::DuplicateTryBlockException(name.join(".")),
Range::from_located(expr),
));
}
}
}
}

View File

@@ -4,9 +4,9 @@ use crate::ast::types::Range;
use crate::autofix::Fix;
use crate::checkers::ast::Checker;
use crate::checks::{Check, CheckKind};
use crate::code_gen::SourceGenerator;
use crate::python::identifiers::IDENTIFIER_REGEX;
use crate::python::keyword::KWLIST;
use crate::source_code_generator::SourceCodeGenerator;
fn attribute(value: &Expr, attr: &str) -> Expr {
Expr::new(
@@ -46,7 +46,8 @@ pub fn getattr_with_constant(checker: &mut Checker, expr: &Expr, func: &Expr, ar
let mut check = Check::new(CheckKind::GetAttrWithConstant, Range::from_located(expr));
if checker.patch(check.kind.code()) {
let mut generator = SourceGenerator::new();
let mut generator =
SourceCodeGenerator::new(checker.style.indentation(), checker.style.quote());
generator.unparse_expr(&attribute(obj, value), 0);
if let Ok(content) = generator.generate() {
check.amend(Fix::replacement(

View File

@@ -4,7 +4,7 @@ use crate::ast::types::Range;
use crate::autofix::Fix;
use crate::checkers::ast::Checker;
use crate::checks::{Check, CheckKind};
use crate::code_gen::SourceGenerator;
use crate::source_code_generator::SourceCodeGenerator;
/// B013
pub fn redundant_tuple_in_exception_handler(checker: &mut Checker, handlers: &[Excepthandler]) {
@@ -23,7 +23,8 @@ pub fn redundant_tuple_in_exception_handler(checker: &mut Checker, handlers: &[E
Range::from_located(type_),
);
if checker.patch(check.kind.code()) {
let mut generator = SourceGenerator::new();
let mut generator =
SourceCodeGenerator::new(checker.style.indentation(), checker.style.quote());
generator.unparse_expr(elt, 0);
if let Ok(content) = generator.generate() {
check.amend(Fix::replacement(

View File

@@ -6,11 +6,17 @@ use crate::ast::types::Range;
use crate::autofix::Fix;
use crate::checkers::ast::Checker;
use crate::checks::{Check, CheckKind};
use crate::code_gen::SourceGenerator;
use crate::python::identifiers::IDENTIFIER_REGEX;
use crate::python::keyword::KWLIST;
use crate::source_code_generator::SourceCodeGenerator;
use crate::source_code_style::SourceCodeStyleDetector;
fn assignment(obj: &Expr, name: &str, value: &Expr) -> Result<String> {
fn assignment(
obj: &Expr,
name: &str,
value: &Expr,
stylist: &SourceCodeStyleDetector,
) -> Result<String> {
let stmt = Stmt::new(
Location::default(),
Location::default(),
@@ -28,7 +34,7 @@ fn assignment(obj: &Expr, name: &str, value: &Expr) -> Result<String> {
type_comment: None,
},
);
let mut generator = SourceGenerator::new();
let mut generator = SourceCodeGenerator::new(stylist.indentation(), stylist.quote());
generator.unparse_stmt(&stmt);
generator.generate().map_err(std::convert::Into::into)
}
@@ -63,7 +69,7 @@ pub fn setattr_with_constant(checker: &mut Checker, expr: &Expr, func: &Expr, ar
if expr == child.as_ref() {
let mut check = Check::new(CheckKind::SetAttrWithConstant, Range::from_located(expr));
if checker.patch(check.kind.code()) {
match assignment(obj, name, value) {
match assignment(obj, name, value, checker.style) {
Ok(content) => check.amend(Fix::replacement(
content,
expr.location,

View File

@@ -1,16 +1,19 @@
//! Settings for the `flake8-bugbear` plugin.
use ruff_macros::ConfigurationOptions;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Default, ConfigurationOptions)]
#[serde(deny_unknown_fields, rename_all = "kebab-case")]
#[derive(
Debug, PartialEq, Eq, Serialize, Deserialize, Default, ConfigurationOptions, JsonSchema,
)]
#[serde(
deny_unknown_fields,
rename_all = "kebab-case",
rename = "Flake8BugbearOptions"
)]
pub struct Options {
#[option(
doc = r#"
Additional callable functions to consider "immutable" when evaluating, e.g.,
`no-mutable-default-argument` checks (`B006`).
"#,
default = r#"[]"#,
value_type = "Vec<String>",
example = r#"
@@ -18,6 +21,8 @@ pub struct Options {
extend-immutable-calls = ["fastapi.Depends", "fastapi.Query"]
"#
)]
/// Additional callable functions to consider "immutable" when evaluating,
/// e.g., `no-mutable-default-argument` checks (`B006`).
pub extend_immutable_calls: Option<Vec<String>>,
}

View File

@@ -25,7 +25,7 @@ expression: checks
row: 10
column: 12
fix:
content: "raise AssertionError('message')"
content: "raise AssertionError(\"message\")"
location:
row: 10
column: 0

View File

@@ -5,37 +5,37 @@ expression: checks
- kind:
DuplicateTryBlockException: ValueError
location:
row: 15
column: 0
row: 19
column: 7
end_location:
row: 20
column: 9
row: 19
column: 17
fix: ~
- kind:
DuplicateTryBlockException: pickle.PickleError
location:
row: 22
column: 0
row: 28
column: 7
end_location:
row: 29
column: 9
fix: ~
- kind:
DuplicateTryBlockException: TypeError
location:
row: 31
column: 0
end_location:
row: 38
column: 9
row: 28
column: 25
fix: ~
- kind:
DuplicateTryBlockException: ValueError
location:
row: 31
column: 0
row: 35
column: 7
end_location:
row: 38
column: 9
row: 35
column: 17
fix: ~
- kind:
DuplicateTryBlockException: TypeError
location:
row: 37
column: 17
end_location:
row: 37
column: 26
fix: ~

View File

@@ -19,20 +19,14 @@ pub fn call_datetime_without_tzinfo(
return;
}
// no args / no args unqualified
if args.len() < 8 && keywords.is_empty() {
// No positional arg: keyword is missing or constant None.
if args.len() < 8 && !has_non_none_keyword(keywords, "tzinfo") {
checker.add_check(Check::new(CheckKind::CallDatetimeWithoutTzinfo, location));
return;
}
// none args
if args.len() == 8 && is_const_none(&args[7]) {
checker.add_check(Check::new(CheckKind::CallDatetimeWithoutTzinfo, location));
return;
}
// no kwargs / none kwargs
if !has_non_none_keyword(keywords, "tzinfo") {
// Positional arg: is constant None.
if args.len() >= 8 && is_const_none(&args[7]) {
checker.add_check(Check::new(CheckKind::CallDatetimeWithoutTzinfo, location));
}
}

View File

@@ -20,26 +20,26 @@ expression: checks
fix: ~
- kind: CallDatetimeWithoutTzinfo
location:
row: 10
row: 13
column: 0
end_location:
row: 10
row: 13
column: 37
fix: ~
- kind: CallDatetimeWithoutTzinfo
location:
row: 13
row: 16
column: 0
end_location:
row: 13
row: 16
column: 42
fix: ~
- kind: CallDatetimeWithoutTzinfo
location:
row: 18
row: 21
column: 0
end_location:
row: 18
row: 21
column: 29
fix: ~

View File

@@ -1,46 +0,0 @@
use rustpython_ast::{Constant, Expr, ExprKind};
use crate::ast::types::Range;
use crate::checks::{Check, CheckKind};
pub fn check_string_in_exception(exc: &Expr, max_string_length: usize) -> Vec<Check> {
let mut checks = vec![];
if let ExprKind::Call { args, .. } = &exc.node {
if let Some(first) = args.first() {
match &first.node {
// Check for string literals
ExprKind::Constant {
value: Constant::Str(string),
..
} => {
if string.len() > max_string_length {
checks.push(Check::new(
CheckKind::RawStringInException,
Range::from_located(first),
));
}
}
// Check for f-strings
ExprKind::JoinedStr { .. } => checks.push(Check::new(
CheckKind::FStringInException,
Range::from_located(first),
)),
// Check for .format() calls
ExprKind::Call { func, .. } => {
if let ExprKind::Attribute { value, attr, .. } = &func.node {
if attr == "format" && matches!(value.node, ExprKind::Constant { .. }) {
checks.push(Check::new(
CheckKind::DotFormatInException,
Range::from_located(first),
));
}
}
}
_ => {}
}
}
}
checks
}

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