Compare commits
40 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cdb4700813 | ||
|
|
ea4d54a90f | ||
|
|
51b917cfbf | ||
|
|
c880d744fd | ||
|
|
84d1df08be | ||
|
|
b9bb5acff8 | ||
|
|
ca7c3c2175 | ||
|
|
8891e2e62b | ||
|
|
53265e0ed4 | ||
|
|
072849a8a9 | ||
|
|
70ea4b25e8 | ||
|
|
30e133f3d8 | ||
|
|
aa812de07e | ||
|
|
57ac6a8444 | ||
|
|
a6566b1b34 | ||
|
|
580da1fa6b | ||
|
|
b78b6f275e | ||
|
|
6868bb46f5 | ||
|
|
601848d9a8 | ||
|
|
f4da7635f0 | ||
|
|
74a8a218f3 | ||
|
|
1730f2a603 | ||
|
|
a4862857de | ||
|
|
6e88c60c46 | ||
|
|
2ed1f78873 | ||
|
|
f3bf008aed | ||
|
|
3b4aaa53c1 | ||
|
|
6abf71639f | ||
|
|
c0845a8c28 | ||
|
|
019ecc4add | ||
|
|
f4cf48d885 | ||
|
|
005f5d7911 | ||
|
|
2fce580693 | ||
|
|
8862565a0f | ||
|
|
5bf6da0db7 | ||
|
|
ee655c1a88 | ||
|
|
2236b4bd59 | ||
|
|
fbf311f7d5 | ||
|
|
8c18b28bc4 | ||
|
|
42031b8574 |
3
.github/workflows/ruff.yaml
vendored
3
.github/workflows/ruff.yaml
vendored
@@ -293,3 +293,6 @@ jobs:
|
||||
run: |
|
||||
pip install --upgrade twine
|
||||
twine upload --skip-existing *
|
||||
- name: Update pre-commit mirror
|
||||
run: |
|
||||
curl -X POST -H "Accept: application/vnd.github+json" -H "Authorization: Bearer ${{ secrets.RUFF_PRE_COMMIT_PAT }}" -H "X-GitHub-Api-Version: 2022-11-28" https://api.github.com/repos/charliermarsh/ruff-pre-commit/dispatches --data '{"event_type": "pypi_release"}'
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
repos:
|
||||
- repo: https://github.com/charliermarsh/ruff-pre-commit
|
||||
rev: v0.0.223
|
||||
rev: v0.0.225
|
||||
hooks:
|
||||
- id: ruff
|
||||
|
||||
|
||||
@@ -1,5 +1,14 @@
|
||||
# Breaking Changes
|
||||
|
||||
## 0.0.225
|
||||
|
||||
### `@functools.cache` rewrites have been moved to a standalone rule (`UP033`) ([#1938](https://github.com/charliermarsh/ruff/pull/1938))
|
||||
|
||||
Previously, `UP011` handled both `@functools.lru_cache()`-to-`@functools.lru_cache` conversions,
|
||||
_and_ `@functools.lru_cache(maxsize=None)`-to-`@functools.cache` conversions. The latter has been
|
||||
moved out to its own rule (`UP033`). As such, some `# noqa: UP011` comments may need to be updated
|
||||
to reflect the change in rule code.
|
||||
|
||||
## 0.0.222
|
||||
|
||||
### `--max-complexity` has been removed from the CLI ([#1877](https://github.com/charliermarsh/ruff/pull/1877))
|
||||
|
||||
@@ -59,7 +59,7 @@ There are four phases to adding a new lint rule:
|
||||
1. Define the violation struct in `src/violations.rs` (e.g., `ModuleImportNotAtTopOfFile`).
|
||||
2. Map the violation struct to a rule code in `src/registry.rs` (e.g., `E402`).
|
||||
3. Define the logic for triggering the violation 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).
|
||||
`src/checkers/tokens.rs` (for token-based checks), `src/checkers/lines.rs` (for text-based checks) or `src/checkers/filesystem.rs` (for filesystem-based checks).
|
||||
4. Add a test fixture.
|
||||
5. Update the generated files (documentation and generated code).
|
||||
|
||||
|
||||
10
Cargo.lock
generated
10
Cargo.lock
generated
@@ -735,7 +735,7 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
|
||||
|
||||
[[package]]
|
||||
name = "flake8-to-ruff"
|
||||
version = "0.0.223"
|
||||
version = "0.0.225"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap 4.0.32",
|
||||
@@ -1906,7 +1906,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ruff"
|
||||
version = "0.0.223"
|
||||
version = "0.0.225"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bitflags",
|
||||
@@ -1958,7 +1958,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ruff_cli"
|
||||
version = "0.0.223"
|
||||
version = "0.0.225"
|
||||
dependencies = [
|
||||
"annotate-snippets 0.9.1",
|
||||
"anyhow",
|
||||
@@ -1995,7 +1995,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ruff_dev"
|
||||
version = "0.0.223"
|
||||
version = "0.0.225"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap 4.0.32",
|
||||
@@ -2016,7 +2016,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ruff_macros"
|
||||
version = "0.0.223"
|
||||
version = "0.0.225"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"proc-macro2",
|
||||
|
||||
@@ -8,7 +8,7 @@ default-members = [".", "ruff_cli"]
|
||||
|
||||
[package]
|
||||
name = "ruff"
|
||||
version = "0.0.223"
|
||||
version = "0.0.225"
|
||||
authors = ["Charlie Marsh <charlie.r.marsh@gmail.com>"]
|
||||
edition = "2021"
|
||||
rust-version = "1.65.0"
|
||||
@@ -46,7 +46,7 @@ once_cell = { version = "1.16.0" }
|
||||
path-absolutize = { version = "3.0.14", features = ["once_cell_cache", "use_unix_paths_on_wasm"] }
|
||||
regex = { version = "1.6.0" }
|
||||
ropey = { version = "1.5.0", features = ["cr_lines", "simd"], default-features = false }
|
||||
ruff_macros = { version = "0.0.223", path = "ruff_macros" }
|
||||
ruff_macros = { version = "0.0.225", path = "ruff_macros" }
|
||||
rustc-hash = { version = "1.1.0" }
|
||||
rustpython-ast = { features = ["unparse"], git = "https://github.com/RustPython/RustPython.git", rev = "acbc517b55406c76da83d7b2711941d8d3f65b87" }
|
||||
rustpython-common = { git = "https://github.com/RustPython/RustPython.git", rev = "acbc517b55406c76da83d7b2711941d8d3f65b87" }
|
||||
|
||||
208
README.md
208
README.md
@@ -10,9 +10,9 @@ An extremely fast Python linter, written in Rust.
|
||||
|
||||
<p align="center">
|
||||
<picture align="center">
|
||||
<source media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/1309177/210156880-a97c2a0d-2c03-4393-8695-36547935a94e.svg">
|
||||
<source media="(prefers-color-scheme: light)" srcset="https://user-images.githubusercontent.com/1309177/210156881-a88fd142-5008-4695-9407-d028cec3eff7.svg">
|
||||
<img alt="Shows a bar chart with benchmark results." src="https://user-images.githubusercontent.com/1309177/210156881-a88fd142-5008-4695-9407-d028cec3eff7.svg">
|
||||
<source media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/1309177/212613422-7faaf278-706b-4294-ad92-236ffcab3430.svg">
|
||||
<source media="(prefers-color-scheme: light)" srcset="https://user-images.githubusercontent.com/1309177/212613257-5f4bca12-6d6b-4c79-9bac-51a4c6d08928.svg">
|
||||
<img alt="Shows a bar chart with benchmark results." src="https://user-images.githubusercontent.com/1309177/212613257-5f4bca12-6d6b-4c79-9bac-51a4c6d08928.svg">
|
||||
</picture>
|
||||
</p>
|
||||
|
||||
@@ -74,6 +74,13 @@ of [FastAPI](https://github.com/tiangolo/fastapi):
|
||||
> Ruff is so fast that sometimes I add an intentional bug in the code just to confirm it's actually
|
||||
> running and checking the code.
|
||||
|
||||
[**Nick Schrock**](https://twitter.com/schrockn/status/1612615862904827904), founder of [Elementl](https://www.elementl.com/),
|
||||
co-creator of [GraphQL](https://graphql.org/):
|
||||
|
||||
> Why is Ruff a gamechanger? Primarily because it is nearly 1000x faster. Literally. Not a typo. On
|
||||
> our largest module (dagster itself, 250k LOC) pylint takes about 2.5 minutes, parallelized across 4
|
||||
> cores on my M1. Running ruff against our *entire* codebase takes .4 seconds.
|
||||
|
||||
[**Bryan Van de Ven**](https://github.com/bokeh/bokeh/pull/12605), co-creator
|
||||
of [Bokeh](https://github.com/bokeh/bokeh/), original author
|
||||
of [Conda](https://docs.conda.io/en/latest/):
|
||||
@@ -82,7 +89,13 @@ of [Conda](https://docs.conda.io/en/latest/):
|
||||
> ~20s. This is an enormous quality of life improvement for local dev. It's fast enough that I added
|
||||
> it as an actual commit hook, which is terrific.
|
||||
|
||||
[**Tim Abbott**](https://github.com/charliermarsh/ruff/issues/465#issuecomment-1317400028), lead developer of [Zulip](https://github.com/zulip/zulip):
|
||||
[**Timothy Crosley**](https://twitter.com/timothycrosley/status/1606420868514877440),
|
||||
creator of [isort](https://github.com/PyCQA/isort):
|
||||
|
||||
> Just switched my first project to Ruff. Only one downside so far: it's so fast I couldn't believe it was working till I intentionally introduced some errors.
|
||||
|
||||
[**Tim Abbott**](https://github.com/charliermarsh/ruff/issues/465#issuecomment-1317400028), lead
|
||||
developer of [Zulip](https://github.com/zulip/zulip):
|
||||
|
||||
> This is just ridiculously fast... `ruff` is amazing.
|
||||
|
||||
@@ -124,6 +137,7 @@ of [Conda](https://docs.conda.io/en/latest/):
|
||||
1. [Pylint (PLC, PLE, PLR, PLW)](#pylint-plc-ple-plr-plw)
|
||||
1. [flake8-pie (PIE)](#flake8-pie-pie)
|
||||
1. [flake8-commas (COM)](#flake8-commas-com)
|
||||
1. [flake8-no-pep420 (INP)](#flake8-no-pep420-inp)
|
||||
1. [Ruff-specific rules (RUF)](#ruff-specific-rules-ruf)<!-- End auto-generated table of contents. -->
|
||||
1. [Editor Integrations](#editor-integrations)
|
||||
1. [FAQ](#faq)
|
||||
@@ -185,7 +199,7 @@ Ruff also works with [pre-commit](https://pre-commit.com):
|
||||
```yaml
|
||||
- repo: https://github.com/charliermarsh/ruff-pre-commit
|
||||
# Ruff version.
|
||||
rev: 'v0.0.223'
|
||||
rev: 'v0.0.225'
|
||||
hooks:
|
||||
- id: ruff
|
||||
# Respect `exclude` and `extend-exclude` settings.
|
||||
@@ -692,7 +706,7 @@ For more, see [pyupgrade](https://pypi.org/project/pyupgrade/3.2.0/) on PyPI.
|
||||
| UP008 | SuperCallWithParameters | Use `super()` instead of `super(__class__, self)` | 🛠 |
|
||||
| UP009 | PEP3120UnnecessaryCodingComment | UTF-8 encoding declaration is unnecessary | 🛠 |
|
||||
| UP010 | UnnecessaryFutureImport | Unnecessary `__future__` import `...` for target Python version | 🛠 |
|
||||
| UP011 | UnnecessaryLRUCacheParams | Unnecessary parameters to `functools.lru_cache` | 🛠 |
|
||||
| UP011 | LRUCacheWithoutParameters | Unnecessary parameters to `functools.lru_cache` | 🛠 |
|
||||
| UP012 | UnnecessaryEncodeUTF8 | Unnecessary call to `encode` as UTF-8 | 🛠 |
|
||||
| UP013 | ConvertTypedDictFunctionalToClass | Convert `...` from `TypedDict` functional to class syntax | 🛠 |
|
||||
| UP014 | ConvertNamedTupleFunctionalToClass | Convert `...` from `NamedTuple` functional to class syntax | 🛠 |
|
||||
@@ -712,6 +726,8 @@ For more, see [pyupgrade](https://pypi.org/project/pyupgrade/3.2.0/) on PyPI.
|
||||
| UP028 | RewriteYieldFrom | Replace `yield` over `for` loop with `yield from` | 🛠 |
|
||||
| UP029 | UnnecessaryBuiltinImport | Unnecessary builtin import: `...` | 🛠 |
|
||||
| UP030 | FormatLiterals | Use implicit references for positional format fields | 🛠 |
|
||||
| UP032 | FString | Use f-string instead of `format` call | 🛠 |
|
||||
| UP033 | FunctoolsCache | Use `@functools.cache` instead of `@functools.lru_cache(maxsize=None)` | 🛠 |
|
||||
|
||||
### pep8-naming (N)
|
||||
|
||||
@@ -842,7 +858,7 @@ For more, see [flake8-bugbear](https://pypi.org/project/flake8-bugbear/22.10.27/
|
||||
| B025 | DuplicateTryBlockException | try-except block with duplicate exception `Exception` | |
|
||||
| B026 | StarArgUnpackingAfterKeywordArg | Star-arg unpacking after a keyword argument is strongly discouraged | |
|
||||
| B027 | EmptyMethodWithoutAbstractDecorator | `...` is an empty method in an abstract base class, but has no abstract decorator | |
|
||||
| B904 | RaiseWithoutFromInsideExcept | Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling | |
|
||||
| B904 | RaiseWithoutFromInsideExcept | Within an except clause, raise exceptions with `raise ... from err` or `raise ... from None` to distinguish them from errors in exception handling | |
|
||||
| B905 | ZipWithoutExplicitStrict | `zip()` without an explicit `strict=` parameter | |
|
||||
|
||||
### flake8-builtins (A)
|
||||
@@ -908,6 +924,8 @@ For more, see [flake8-implicit-str-concat](https://pypi.org/project/flake8-impli
|
||||
|
||||
### flake8-import-conventions (ICN)
|
||||
|
||||
For more, see [flake8-import-conventions](https://github.com/joaopalmeiro/flake8-import-conventions) on GitHub.
|
||||
|
||||
| Code | Name | Message | Fix |
|
||||
| ---- | ---- | ------- | --- |
|
||||
| ICN001 | ImportAliasIsNotConventional | `...` should be imported as `...` | |
|
||||
@@ -1018,7 +1036,7 @@ For more, see [flake8-tidy-imports](https://pypi.org/project/flake8-tidy-imports
|
||||
| Code | Name | Message | Fix |
|
||||
| ---- | ---- | ------- | --- |
|
||||
| TID251 | BannedApi | `...` is banned: ... | |
|
||||
| TID252 | BannedRelativeImport | Relative imports are banned | |
|
||||
| TID252 | RelativeImports | Relative imports are banned | |
|
||||
|
||||
### flake8-unused-arguments (ARG)
|
||||
|
||||
@@ -1128,6 +1146,7 @@ For more, see [flake8-pie](https://pypi.org/project/flake8-pie/0.16.0/) on PyPI.
|
||||
| ---- | ---- | ------- | --- |
|
||||
| PIE790 | NoUnnecessaryPass | Unnecessary `pass` statement | 🛠 |
|
||||
| PIE794 | DupeClassFieldDefinitions | Class field `...` is defined multiple times | 🛠 |
|
||||
| PIE796 | PreferUniqueEnums | Enum contains duplicate value: `...` | |
|
||||
| PIE807 | PreferListBuiltin | Prefer `list()` over useless lambda | 🛠 |
|
||||
|
||||
### flake8-commas (COM)
|
||||
@@ -1140,6 +1159,14 @@ For more, see [flake8-commas](https://pypi.org/project/flake8-commas/2.1.0/) on
|
||||
| COM818 | TrailingCommaOnBareTupleProhibited | Trailing comma on bare tuple prohibited | |
|
||||
| COM819 | TrailingCommaProhibited | Trailing comma prohibited | 🛠 |
|
||||
|
||||
### flake8-no-pep420 (INP)
|
||||
|
||||
For more, see [flake8-no-pep420](https://pypi.org/project/flake8-boolean-trap/2.3.0/) on PyPI.
|
||||
|
||||
| Code | Name | Message | Fix |
|
||||
| ---- | ---- | ------- | --- |
|
||||
| INP001 | ImplicitNamespacePackage | File `...` is part of an implicit namespace package. Add an `__init__.py`. | |
|
||||
|
||||
### Ruff-specific rules (RUF)
|
||||
|
||||
| Code | Name | Message | Fix |
|
||||
@@ -1433,6 +1460,7 @@ natively, including:
|
||||
- [`flake8-errmsg`](https://pypi.org/project/flake8-errmsg/)
|
||||
- [`flake8-implicit-str-concat`](https://pypi.org/project/flake8-implicit-str-concat/)
|
||||
- [`flake8-import-conventions`](https://github.com/joaopalmeiro/flake8-import-conventions)
|
||||
- [`flake8-no-pep420`](https://pypi.org/project/flake8-no-pep420)
|
||||
- [`flake8-pie`](https://pypi.org/project/flake8-pie/) ([#1543](https://github.com/charliermarsh/ruff/issues/1543))
|
||||
- [`flake8-print`](https://pypi.org/project/flake8-print/)
|
||||
- [`flake8-quotes`](https://pypi.org/project/flake8-quotes/)
|
||||
@@ -1442,6 +1470,7 @@ natively, including:
|
||||
- [`flake8-tidy-imports`](https://pypi.org/project/flake8-tidy-imports/)
|
||||
- [`isort`](https://pypi.org/project/isort/)
|
||||
- [`mccabe`](https://pypi.org/project/mccabe/)
|
||||
- [`pandas-vet`](https://pypi.org/project/pandas-vet/)
|
||||
- [`pep8-naming`](https://pypi.org/project/pep8-naming/)
|
||||
- [`pydocstyle`](https://pypi.org/project/pydocstyle/)
|
||||
- [`pygrep-hooks`](https://github.com/pre-commit/pygrep-hooks) ([#980](https://github.com/charliermarsh/ruff/issues/980))
|
||||
@@ -1499,6 +1528,7 @@ Today, Ruff can be used to replace Flake8 when used with any of the following pl
|
||||
- [`flake8-errmsg`](https://pypi.org/project/flake8-errmsg/)
|
||||
- [`flake8-implicit-str-concat`](https://pypi.org/project/flake8-implicit-str-concat/)
|
||||
- [`flake8-import-conventions`](https://github.com/joaopalmeiro/flake8-import-conventions)
|
||||
- [`flake8-no-pep420`](https://pypi.org/project/flake8-no-pep420)
|
||||
- [`flake8-pie`](https://pypi.org/project/flake8-pie/) ([#1543](https://github.com/charliermarsh/ruff/issues/1543))
|
||||
- [`flake8-print`](https://pypi.org/project/flake8-print/)
|
||||
- [`flake8-quotes`](https://pypi.org/project/flake8-quotes/)
|
||||
@@ -1507,6 +1537,7 @@ Today, Ruff can be used to replace Flake8 when used with any of the following pl
|
||||
- [`flake8-super`](https://pypi.org/project/flake8-super/)
|
||||
- [`flake8-tidy-imports`](https://pypi.org/project/flake8-tidy-imports/)
|
||||
- [`mccabe`](https://pypi.org/project/mccabe/)
|
||||
- [`pandas-vet`](https://pypi.org/project/pandas-vet/)
|
||||
- [`pep8-naming`](https://pypi.org/project/pep8-naming/)
|
||||
- [`pydocstyle`](https://pypi.org/project/pydocstyle/)
|
||||
|
||||
@@ -1642,57 +1673,28 @@ which makes it a good target for benchmarking.
|
||||
git clone --branch 3.10 https://github.com/python/cpython.git resources/test/cpython
|
||||
```
|
||||
|
||||
Add this `pyproject.toml` to the CPython directory:
|
||||
|
||||
```toml
|
||||
[tool.ruff]
|
||||
line-length = 88
|
||||
extend-exclude = [
|
||||
"Lib/lib2to3/tests/data/bom.py",
|
||||
"Lib/lib2to3/tests/data/crlf.py",
|
||||
"Lib/lib2to3/tests/data/different_encoding.py",
|
||||
"Lib/lib2to3/tests/data/false_encoding.py",
|
||||
"Lib/lib2to3/tests/data/py2_test_grammar.py",
|
||||
"Lib/test/bad_coding2.py",
|
||||
"Lib/test/badsyntax_3131.py",
|
||||
"Lib/test/badsyntax_pep3120.py",
|
||||
"Lib/test/encoded_modules/module_iso_8859_1.py",
|
||||
"Lib/test/encoded_modules/module_koi8_r.py",
|
||||
"Lib/test/test_fstring.py",
|
||||
"Lib/test/test_grammar.py",
|
||||
"Lib/test/test_importlib/test_util.py",
|
||||
"Lib/test/test_named_expressions.py",
|
||||
"Lib/test/test_patma.py",
|
||||
"Lib/test/test_source_encoding.py",
|
||||
"Tools/c-analyzer/c_parser/parser/_delim.py",
|
||||
"Tools/i18n/pygettext.py",
|
||||
"Tools/test2to3/maintest.py",
|
||||
"Tools/test2to3/setup.py",
|
||||
"Tools/test2to3/test/test_foo.py",
|
||||
"Tools/test2to3/test2to3/hello.py",
|
||||
]
|
||||
```
|
||||
|
||||
Next, to benchmark the release build:
|
||||
To benchmark the release build:
|
||||
|
||||
```shell
|
||||
cargo build --release
|
||||
|
||||
hyperfine --ignore-failure --warmup 10 --runs 100 \
|
||||
cargo build --release && hyperfine --ignore-failure --warmup 10 \
|
||||
"./target/release/ruff ./resources/test/cpython/ --no-cache" \
|
||||
"./target/release/ruff ./resources/test/cpython/"
|
||||
|
||||
Benchmark 1: ./target/release/ruff ./resources/test/cpython/ --no-cache
|
||||
Time (mean ± σ): 297.4 ms ± 4.9 ms [User: 2460.0 ms, System: 67.2 ms]
|
||||
Range (min … max): 287.7 ms … 312.1 ms 100 runs
|
||||
Time (mean ± σ): 293.8 ms ± 3.2 ms [User: 2384.6 ms, System: 90.3 ms]
|
||||
Range (min … max): 289.9 ms … 301.6 ms 10 runs
|
||||
|
||||
Warning: Ignoring non-zero exit code.
|
||||
|
||||
Benchmark 2: ./target/release/ruff ./resources/test/cpython/
|
||||
Time (mean ± σ): 79.6 ms ± 7.3 ms [User: 59.7 ms, System: 356.1 ms]
|
||||
Range (min … max): 62.4 ms … 111.2 ms 100 runs
|
||||
Time (mean ± σ): 48.0 ms ± 3.1 ms [User: 65.2 ms, System: 124.7 ms]
|
||||
Range (min … max): 45.0 ms … 66.7 ms 62 runs
|
||||
|
||||
Warning: Ignoring non-zero exit code.
|
||||
|
||||
Summary
|
||||
'./target/release/ruff ./resources/test/cpython/' ran
|
||||
6.12 ± 0.41 times faster than './target/release/ruff ./resources/test/cpython/ --no-cache'
|
||||
```
|
||||
|
||||
To benchmark against the ecosystem's existing tools:
|
||||
@@ -1700,73 +1702,89 @@ To benchmark against the ecosystem's existing tools:
|
||||
```shell
|
||||
hyperfine --ignore-failure --warmup 5 \
|
||||
"./target/release/ruff ./resources/test/cpython/ --no-cache" \
|
||||
"pylint --recursive=y resources/test/cpython/" \
|
||||
"pyflakes resources/test/cpython" \
|
||||
"autoflake --recursive --expand-star-imports --remove-all-unused-imports --remove-unused-variables --remove-duplicate-keys resources/test/cpython" \
|
||||
"pycodestyle resources/test/cpython" \
|
||||
"flake8 resources/test/cpython" \
|
||||
"python -m scripts.run_flake8 resources/test/cpython"
|
||||
```
|
||||
"flake8 resources/test/cpython"
|
||||
|
||||
In order, these evaluate:
|
||||
|
||||
- Ruff
|
||||
- Pylint
|
||||
- Pyflakes
|
||||
- autoflake
|
||||
- pycodestyle
|
||||
- Flake8
|
||||
- Flake8, with a hack to enable multiprocessing on macOS
|
||||
|
||||
(You can `poetry install` from `./scripts` to create a working environment for the above.)
|
||||
|
||||
```shell
|
||||
Benchmark 1: ./target/release/ruff ./resources/test/cpython/ --no-cache
|
||||
Time (mean ± σ): 297.9 ms ± 7.0 ms [User: 2436.6 ms, System: 65.9 ms]
|
||||
Range (min … max): 289.9 ms … 314.6 ms 10 runs
|
||||
Time (mean ± σ): 294.3 ms ± 3.3 ms [User: 2467.5 ms, System: 89.6 ms]
|
||||
Range (min … max): 291.1 ms … 302.8 ms 10 runs
|
||||
|
||||
Warning: Ignoring non-zero exit code.
|
||||
|
||||
Benchmark 2: pylint --recursive=y resources/test/cpython/
|
||||
Time (mean ± σ): 37.634 s ± 0.225 s [User: 36.728 s, System: 0.853 s]
|
||||
Range (min … max): 37.201 s … 38.106 s 10 runs
|
||||
Benchmark 2: pyflakes resources/test/cpython
|
||||
Time (mean ± σ): 15.786 s ± 0.143 s [User: 15.560 s, System: 0.214 s]
|
||||
Range (min … max): 15.640 s … 16.157 s 10 runs
|
||||
|
||||
Warning: Ignoring non-zero exit code.
|
||||
|
||||
Benchmark 3: pyflakes resources/test/cpython
|
||||
Time (mean ± σ): 40.950 s ± 0.449 s [User: 40.688 s, System: 0.229 s]
|
||||
Range (min … max): 40.348 s … 41.671 s 10 runs
|
||||
Benchmark 3: autoflake --recursive --expand-star-imports --remove-all-unused-imports --remove-unused-variables --remove-duplicate-keys resources/test/cpython
|
||||
Time (mean ± σ): 6.175 s ± 0.169 s [User: 54.102 s, System: 1.057 s]
|
||||
Range (min … max): 5.950 s … 6.391 s 10 runs
|
||||
|
||||
Benchmark 4: pycodestyle resources/test/cpython
|
||||
Time (mean ± σ): 46.921 s ± 0.508 s [User: 46.699 s, System: 0.202 s]
|
||||
Range (min … max): 46.171 s … 47.863 s 10 runs
|
||||
|
||||
Warning: Ignoring non-zero exit code.
|
||||
|
||||
Benchmark 4: autoflake --recursive --expand-star-imports --remove-all-unused-imports --remove-unused-variables --remove-duplicate-keys resources/test/cpython
|
||||
Time (mean ± σ): 11.562 s ± 0.160 s [User: 107.022 s, System: 1.143 s]
|
||||
Range (min … max): 11.417 s … 11.917 s 10 runs
|
||||
|
||||
Benchmark 5: pycodestyle resources/test/cpython
|
||||
Time (mean ± σ): 67.428 s ± 0.985 s [User: 67.199 s, System: 0.203 s]
|
||||
Range (min … max): 65.313 s … 68.496 s 10 runs
|
||||
Benchmark 5: flake8 resources/test/cpython
|
||||
Time (mean ± σ): 12.260 s ± 0.321 s [User: 102.934 s, System: 1.230 s]
|
||||
Range (min … max): 11.848 s … 12.933 s 10 runs
|
||||
|
||||
Warning: Ignoring non-zero exit code.
|
||||
|
||||
Benchmark 6: flake8 resources/test/cpython
|
||||
Time (mean ± σ): 116.099 s ± 1.178 s [User: 115.217 s, System: 0.845 s]
|
||||
Range (min … max): 114.180 s … 117.724 s 10 runs
|
||||
|
||||
Warning: Ignoring non-zero exit code.
|
||||
|
||||
Benchmark 7: python -m scripts.run_flake8 resources/test/cpython
|
||||
Time (mean ± σ): 20.477 s ± 0.349 s [User: 142.372 s, System: 1.504 s]
|
||||
Range (min … max): 20.107 s … 21.183 s 10 runs
|
||||
|
||||
Summary
|
||||
'./target/release/ruff ./resources/test/cpython/ --no-cache' ran
|
||||
38.81 ± 1.05 times faster than 'autoflake --recursive --expand-star-imports --remove-all-unused-imports --remove-unused-variables --remove-duplicate-keys resources/test/cpython'
|
||||
68.74 ± 1.99 times faster than 'python -m scripts.run_flake8 resources/test/cpython'
|
||||
126.33 ± 3.05 times faster than 'pylint --recursive=y resources/test/cpython/'
|
||||
137.46 ± 3.55 times faster than 'pyflakes resources/test/cpython'
|
||||
226.35 ± 6.23 times faster than 'pycodestyle resources/test/cpython'
|
||||
389.73 ± 9.92 times faster than 'flake8 resources/test/cpython'
|
||||
20.98 ± 0.62 times faster than 'autoflake --recursive --expand-star-imports --remove-all-unused-imports --remove-unused-variables --remove-duplicate-keys resources/test/cpython'
|
||||
41.66 ± 1.18 times faster than 'flake8 resources/test/cpython'
|
||||
53.64 ± 0.77 times faster than 'pyflakes resources/test/cpython'
|
||||
159.43 ± 2.48 times faster than 'pycodestyle resources/test/cpython'
|
||||
```
|
||||
|
||||
You can run `poetry install` from `./scripts` to create a working environment for the above. All
|
||||
reported benchmarks were computed using the versions specified by `./scripts/pyproject.toml`
|
||||
on Python 3.11.
|
||||
|
||||
To benchmark Pylint, remove the following files from the CPython repository:
|
||||
|
||||
```shell
|
||||
rm Lib/test/bad_coding.py \
|
||||
Lib/test/bad_coding2.py \
|
||||
Lib/test/bad_getattr.py \
|
||||
Lib/test/bad_getattr2.py \
|
||||
Lib/test/bad_getattr3.py \
|
||||
Lib/test/badcert.pem \
|
||||
Lib/test/badkey.pem \
|
||||
Lib/test/badsyntax_3131.py \
|
||||
Lib/test/badsyntax_future10.py \
|
||||
Lib/test/badsyntax_future3.py \
|
||||
Lib/test/badsyntax_future4.py \
|
||||
Lib/test/badsyntax_future5.py \
|
||||
Lib/test/badsyntax_future6.py \
|
||||
Lib/test/badsyntax_future7.py \
|
||||
Lib/test/badsyntax_future8.py \
|
||||
Lib/test/badsyntax_future9.py \
|
||||
Lib/test/badsyntax_pep3120.py \
|
||||
Lib/test/test_asyncio/test_runners.py \
|
||||
Lib/test/test_copy.py \
|
||||
Lib/test/test_inspect.py \
|
||||
Lib/test/test_typing.py
|
||||
```
|
||||
|
||||
Then, from `resources/test/cpython`, run: `time pylint -j 0 -E $(git ls-files '*.py')`. This
|
||||
will execute Pylint with maximum parallelism and only report errors.
|
||||
|
||||
To benchmark Pyupgrade, run the following from `resources/test/cpython`:
|
||||
|
||||
```shell
|
||||
hyperfine --ignore-failure --warmup 5 --prepare "git reset --hard HEAD" \
|
||||
"find . -type f -name \"*.py\" | xargs -P 0 pyupgrade --py311-plus"
|
||||
|
||||
Benchmark 1: find . -type f -name "*.py" | xargs -P 0 pyupgrade --py311-plus
|
||||
Time (mean ± σ): 30.119 s ± 0.195 s [User: 28.638 s, System: 0.390 s]
|
||||
Range (min … max): 29.813 s … 30.356 s 10 runs
|
||||
```
|
||||
|
||||
## Reference
|
||||
|
||||
84
build.rs
Normal file
84
build.rs
Normal file
@@ -0,0 +1,84 @@
|
||||
use std::fs;
|
||||
use std::io::{BufRead, BufReader, BufWriter, Write};
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
fn main() {
|
||||
let out_dir = PathBuf::from(std::env::var_os("OUT_DIR").unwrap());
|
||||
generate_origin_name_and_url(&out_dir);
|
||||
}
|
||||
|
||||
const RULES_SUBMODULE_DOC_PREFIX: &str = "//! Rules from ";
|
||||
|
||||
/// The `src/rules/*/mod.rs` files are expected to have a first line such as the
|
||||
/// following:
|
||||
///
|
||||
/// //! Rules from [Pyflakes](https://pypi.org/project/pyflakes/2.5.0/).
|
||||
///
|
||||
/// This function extracts the link label and url from these comments and
|
||||
/// generates the `name` and `url` functions for the `RuleOrigin` enum
|
||||
/// accordingly, so that they can be used by `ruff_dev::generate_rules_table`.
|
||||
fn generate_origin_name_and_url(out_dir: &Path) {
|
||||
println!("cargo:rerun-if-changed=src/rules/");
|
||||
|
||||
let mut name_match_arms: String = r#"RuleOrigin::Ruff => "Ruff-specific rules","#.into();
|
||||
let mut url_match_arms: String = r#"RuleOrigin::Ruff => None,"#.into();
|
||||
|
||||
for file in fs::read_dir("src/rules/")
|
||||
.unwrap()
|
||||
.flatten()
|
||||
.filter(|f| f.file_type().unwrap().is_dir() && f.file_name() != "ruff")
|
||||
{
|
||||
let mod_rs_path = file.path().join("mod.rs");
|
||||
let mod_rs_path = mod_rs_path.to_str().unwrap();
|
||||
let first_line = BufReader::new(fs::File::open(mod_rs_path).unwrap())
|
||||
.lines()
|
||||
.next()
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
|
||||
let Some(comment) = first_line.strip_prefix(RULES_SUBMODULE_DOC_PREFIX) else {
|
||||
panic!("expected first line in {mod_rs_path} to start with `{RULES_SUBMODULE_DOC_PREFIX}`")
|
||||
};
|
||||
let md_link = comment.trim_end_matches('.');
|
||||
|
||||
let (name, url) = md_link
|
||||
.strip_prefix('[')
|
||||
.unwrap()
|
||||
.strip_suffix(')')
|
||||
.unwrap()
|
||||
.split_once("](")
|
||||
.unwrap();
|
||||
|
||||
let dirname = file.file_name();
|
||||
let dirname = dirname.to_str().unwrap();
|
||||
|
||||
let variant_name = dirname
|
||||
.split('_')
|
||||
.map(|part| match part {
|
||||
"errmsg" => "ErrMsg".to_string(),
|
||||
"mccabe" => "McCabe".to_string(),
|
||||
"pep8" => "PEP8".to_string(),
|
||||
_ => format!("{}{}", part[..1].to_uppercase(), &part[1..]),
|
||||
})
|
||||
.collect::<String>();
|
||||
|
||||
name_match_arms.push_str(&format!(r#"RuleOrigin::{variant_name} => "{name}","#));
|
||||
url_match_arms.push_str(&format!(r#"RuleOrigin::{variant_name} => Some("{url}"),"#));
|
||||
}
|
||||
|
||||
write!(
|
||||
BufWriter::new(fs::File::create(out_dir.join("origin.rs")).unwrap()),
|
||||
"
|
||||
impl RuleOrigin {{
|
||||
pub fn name(&self) -> &'static str {{
|
||||
match self {{ {name_match_arms} }}
|
||||
}}
|
||||
|
||||
pub fn url(&self) -> Option<&'static str> {{
|
||||
match self {{ {url_match_arms} }}
|
||||
}}
|
||||
}}
|
||||
"
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
4
flake8_to_ruff/Cargo.lock
generated
4
flake8_to_ruff/Cargo.lock
generated
@@ -771,7 +771,7 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
|
||||
|
||||
[[package]]
|
||||
name = "flake8_to_ruff"
|
||||
version = "0.0.223"
|
||||
version = "0.0.225"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap",
|
||||
@@ -1975,7 +1975,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ruff"
|
||||
version = "0.0.223"
|
||||
version = "0.0.225"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bincode",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "flake8-to-ruff"
|
||||
version = "0.0.223"
|
||||
version = "0.0.225"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
|
||||
21
licenses/LICENSE_adamchainz_flake8-no-pep420
Normal file
21
licenses/LICENSE_adamchainz_flake8-no-pep420
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2020 Adam Johnson
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -7,7 +7,7 @@ build-backend = "maturin"
|
||||
|
||||
[project]
|
||||
name = "ruff"
|
||||
version = "0.0.223"
|
||||
version = "0.0.225"
|
||||
description = "An extremely fast Python linter, written in Rust."
|
||||
authors = [
|
||||
{ name = "Charlie Marsh", email = "charlie.r.marsh@gmail.com" },
|
||||
@@ -41,9 +41,3 @@ bindings = "bin"
|
||||
manifest-path = "ruff_cli/Cargo.toml"
|
||||
python-source = "python"
|
||||
strip = true
|
||||
|
||||
[tool.setuptools]
|
||||
license-files = [
|
||||
"LICENSE",
|
||||
"licenses/*",
|
||||
]
|
||||
|
||||
0
resources/test/fixtures/flake8_no_pep420/test_fail_empty/example.py
vendored
Normal file
0
resources/test/fixtures/flake8_no_pep420/test_fail_empty/example.py
vendored
Normal file
1
resources/test/fixtures/flake8_no_pep420/test_fail_nonempty/example.py
vendored
Normal file
1
resources/test/fixtures/flake8_no_pep420/test_fail_nonempty/example.py
vendored
Normal file
@@ -0,0 +1 @@
|
||||
print('hi')
|
||||
2
resources/test/fixtures/flake8_no_pep420/test_fail_shebang/example.py
vendored
Normal file
2
resources/test/fixtures/flake8_no_pep420/test_fail_shebang/example.py
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
#!/bin/env/python
|
||||
print('hi')
|
||||
1
resources/test/fixtures/flake8_no_pep420/test_ignored/example.py
vendored
Normal file
1
resources/test/fixtures/flake8_no_pep420/test_ignored/example.py
vendored
Normal file
@@ -0,0 +1 @@
|
||||
import os # noqa: INP001
|
||||
0
resources/test/fixtures/flake8_no_pep420/test_pass/__init__.py
vendored
Normal file
0
resources/test/fixtures/flake8_no_pep420/test_pass/__init__.py
vendored
Normal file
0
resources/test/fixtures/flake8_no_pep420/test_pass/example.py
vendored
Normal file
0
resources/test/fixtures/flake8_no_pep420/test_pass/example.py
vendored
Normal file
66
resources/test/fixtures/flake8_pie/PIE796.py
vendored
Normal file
66
resources/test/fixtures/flake8_pie/PIE796.py
vendored
Normal file
@@ -0,0 +1,66 @@
|
||||
import enum
|
||||
from enum import Enum, unique
|
||||
|
||||
|
||||
class FakeEnum1(enum.Enum):
|
||||
A = "A"
|
||||
B = "B"
|
||||
C = "B" # PIE796
|
||||
|
||||
|
||||
class FakeEnum2(Enum):
|
||||
A = 1
|
||||
B = 2
|
||||
C = 2 # PIE796
|
||||
|
||||
|
||||
class FakeEnum3(str, Enum):
|
||||
A = "1"
|
||||
B = "2"
|
||||
C = "2" # PIE796
|
||||
|
||||
|
||||
class FakeEnum4(Enum):
|
||||
A = 1.0
|
||||
B = 2.5
|
||||
C = 2.5 # PIE796
|
||||
|
||||
|
||||
class FakeEnum5(Enum):
|
||||
A = 1.0
|
||||
B = True
|
||||
C = False
|
||||
D = False # PIE796
|
||||
|
||||
|
||||
class FakeEnum6(Enum):
|
||||
A = 1
|
||||
B = 2
|
||||
C = None
|
||||
D = None # PIE796
|
||||
|
||||
|
||||
@enum.unique
|
||||
class FakeEnum7(enum.Enum):
|
||||
A = "A"
|
||||
B = "B"
|
||||
C = "C"
|
||||
|
||||
|
||||
@unique
|
||||
class FakeEnum8(Enum):
|
||||
A = 1
|
||||
B = 2
|
||||
C = 2 # PIE796
|
||||
|
||||
|
||||
class FakeEnum9(enum.Enum):
|
||||
A = "A"
|
||||
B = "B"
|
||||
C = "C"
|
||||
|
||||
|
||||
class FakeEnum10(enum.Enum):
|
||||
A = enum.auto()
|
||||
B = enum.auto()
|
||||
C = enum.auto()
|
||||
@@ -1,12 +1,35 @@
|
||||
def f():
|
||||
if a: # SIM103
|
||||
# SIM103
|
||||
if a:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
def f():
|
||||
if a: # OK
|
||||
# SIM103
|
||||
if a:
|
||||
return 1
|
||||
elif b:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
def f():
|
||||
# SIM103
|
||||
if a:
|
||||
return 1
|
||||
else:
|
||||
if b:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
def f():
|
||||
# OK
|
||||
if a:
|
||||
foo()
|
||||
return True
|
||||
else:
|
||||
@@ -14,7 +37,8 @@ def f():
|
||||
|
||||
|
||||
def f():
|
||||
if a: # OK
|
||||
# OK
|
||||
if a:
|
||||
return "foo"
|
||||
else:
|
||||
return False
|
||||
|
||||
@@ -41,3 +41,21 @@ except ValueError:
|
||||
pass
|
||||
finally:
|
||||
print('bar')
|
||||
|
||||
try:
|
||||
foo()
|
||||
foo()
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
try:
|
||||
for i in range(3):
|
||||
foo()
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
def bar():
|
||||
try:
|
||||
return foo()
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
@@ -1,6 +1,36 @@
|
||||
f = open('foo.txt') # SIM115
|
||||
import contextlib
|
||||
|
||||
# SIM115
|
||||
f = open("foo.txt")
|
||||
data = f.read()
|
||||
f.close()
|
||||
|
||||
with open('foo.txt') as f: # OK
|
||||
# OK
|
||||
with open("foo.txt") as f:
|
||||
data = f.read()
|
||||
|
||||
# OK
|
||||
with contextlib.ExitStack() as exit_stack:
|
||||
f = exit_stack.enter_context(open("filename"))
|
||||
|
||||
# OK
|
||||
with contextlib.ExitStack() as stack:
|
||||
files = [stack.enter_context(open(fname)) for fname in filenames]
|
||||
close_files = stack.pop_all().close
|
||||
|
||||
# OK
|
||||
with contextlib.AsyncExitStack() as exit_stack:
|
||||
f = await exit_stack.enter_async_context(open("filename"))
|
||||
|
||||
# OK (false negative)
|
||||
with contextlib.ExitStack():
|
||||
f = exit_stack.enter_context(open("filename"))
|
||||
|
||||
# SIM115
|
||||
with contextlib.ExitStack():
|
||||
f = open("filename")
|
||||
|
||||
# OK
|
||||
with contextlib.ExitStack() as exit_stack:
|
||||
exit_stack_ = exit_stack
|
||||
f = exit_stack_.enter_context(open("filename"))
|
||||
|
||||
22
resources/test/fixtures/pyflakes/F841_3.py
vendored
22
resources/test/fixtures/pyflakes/F841_3.py
vendored
@@ -44,3 +44,25 @@ def f():
|
||||
1 / 0
|
||||
except (ValueError, ZeroDivisionError) as x2:
|
||||
pass
|
||||
|
||||
|
||||
def f(a, b):
|
||||
x = (
|
||||
a()
|
||||
if a is not None
|
||||
else b
|
||||
)
|
||||
|
||||
y = \
|
||||
a() if a is not None else b
|
||||
|
||||
|
||||
def f(a, b):
|
||||
x = (
|
||||
a
|
||||
if a is not None
|
||||
else b
|
||||
)
|
||||
|
||||
y = \
|
||||
a if a is not None else b
|
||||
|
||||
67
resources/test/fixtures/pyupgrade/UP011.py
vendored
Normal file
67
resources/test/fixtures/pyupgrade/UP011.py
vendored
Normal file
@@ -0,0 +1,67 @@
|
||||
import functools
|
||||
from functools import lru_cache
|
||||
|
||||
|
||||
@functools.lru_cache()
|
||||
def fixme():
|
||||
pass
|
||||
|
||||
|
||||
@lru_cache()
|
||||
def fixme():
|
||||
pass
|
||||
|
||||
|
||||
@other_decorator
|
||||
@functools.lru_cache()
|
||||
def fixme():
|
||||
pass
|
||||
|
||||
|
||||
@functools.lru_cache()
|
||||
@other_decorator
|
||||
def fixme():
|
||||
pass
|
||||
|
||||
|
||||
@functools.lru_cache(maxsize=None)
|
||||
def ok():
|
||||
pass
|
||||
|
||||
|
||||
@lru_cache(maxsize=None)
|
||||
def ok():
|
||||
pass
|
||||
|
||||
|
||||
@functools.lru_cache(maxsize=64)
|
||||
def ok():
|
||||
pass
|
||||
|
||||
|
||||
@lru_cache(maxsize=64)
|
||||
def ok():
|
||||
pass
|
||||
|
||||
|
||||
def user_func():
|
||||
pass
|
||||
|
||||
|
||||
@lru_cache(user_func)
|
||||
def ok():
|
||||
pass
|
||||
|
||||
|
||||
@lru_cache(user_func, maxsize=None)
|
||||
def ok():
|
||||
pass
|
||||
|
||||
|
||||
def lru_cache(maxsize=None):
|
||||
pass
|
||||
|
||||
|
||||
@lru_cache(maxsize=None)
|
||||
def ok():
|
||||
pass
|
||||
103
resources/test/fixtures/pyupgrade/UP011_0.py
vendored
103
resources/test/fixtures/pyupgrade/UP011_0.py
vendored
@@ -1,103 +0,0 @@
|
||||
import functools
|
||||
from functools import lru_cache
|
||||
|
||||
|
||||
@lru_cache()
|
||||
def fixme1():
|
||||
pass
|
||||
|
||||
|
||||
@other_deco_after
|
||||
@functools.lru_cache()
|
||||
def fixme2():
|
||||
pass
|
||||
|
||||
|
||||
@lru_cache(maxsize=None)
|
||||
def fixme3():
|
||||
pass
|
||||
|
||||
|
||||
@functools.lru_cache(maxsize=None)
|
||||
@other_deco_before
|
||||
def fixme4():
|
||||
pass
|
||||
|
||||
|
||||
@lru_cache( # A
|
||||
) # B
|
||||
def fixme5():
|
||||
pass
|
||||
|
||||
|
||||
@lru_cache(
|
||||
# A
|
||||
) # B
|
||||
def fixme6():
|
||||
pass
|
||||
|
||||
|
||||
@functools.lru_cache(
|
||||
# A
|
||||
maxsize = None) # B
|
||||
def fixme7():
|
||||
pass
|
||||
|
||||
|
||||
@functools.lru_cache(
|
||||
# A1
|
||||
maxsize = None
|
||||
# A2
|
||||
) # B
|
||||
def fixme8():
|
||||
pass
|
||||
|
||||
|
||||
@functools.lru_cache(
|
||||
# A1
|
||||
maxsize =
|
||||
None
|
||||
# A2
|
||||
|
||||
)
|
||||
def fixme9():
|
||||
pass
|
||||
|
||||
|
||||
@functools.lru_cache(
|
||||
# A1
|
||||
maxsize =
|
||||
None
|
||||
# A2
|
||||
)
|
||||
def fixme10():
|
||||
pass
|
||||
|
||||
|
||||
@lru_cache
|
||||
def correct1():
|
||||
pass
|
||||
|
||||
|
||||
@functools.lru_cache
|
||||
def correct2():
|
||||
pass
|
||||
|
||||
|
||||
@functoools.lru_cache(maxsize=64)
|
||||
def correct3():
|
||||
pass
|
||||
|
||||
|
||||
def user_func():
|
||||
pass
|
||||
|
||||
|
||||
@lru_cache(user_func)
|
||||
def correct4():
|
||||
pass
|
||||
|
||||
|
||||
@lru_cache(user_func, maxsize=None)
|
||||
def correct5():
|
||||
pass
|
||||
15
resources/test/fixtures/pyupgrade/UP011_1.py
vendored
15
resources/test/fixtures/pyupgrade/UP011_1.py
vendored
@@ -1,15 +0,0 @@
|
||||
import functools
|
||||
|
||||
|
||||
def lru_cache(maxsize=None):
|
||||
pass
|
||||
|
||||
|
||||
@lru_cache()
|
||||
def dont_fixme():
|
||||
pass
|
||||
|
||||
|
||||
@lru_cache(maxsize=None)
|
||||
def dont_fixme():
|
||||
pass
|
||||
86
resources/test/fixtures/pyupgrade/UP032.py
vendored
Normal file
86
resources/test/fixtures/pyupgrade/UP032.py
vendored
Normal file
@@ -0,0 +1,86 @@
|
||||
###
|
||||
# Errors
|
||||
###
|
||||
|
||||
"{} {}".format(a, b)
|
||||
|
||||
"{1} {0}".format(a, b)
|
||||
|
||||
"{x.y}".format(x=z)
|
||||
|
||||
"{.x} {.y}".format(a, b)
|
||||
|
||||
"{} {}".format(a.b, c.d)
|
||||
|
||||
"{}".format(a())
|
||||
|
||||
"{}".format(a.b())
|
||||
|
||||
"{}".format(a.b().c())
|
||||
|
||||
"hello {}!".format(name)
|
||||
|
||||
"{}{b}{}".format(a, c, b=b)
|
||||
|
||||
"{}".format(0x0)
|
||||
|
||||
"{} {}".format(a, b)
|
||||
|
||||
"""{} {}""".format(a, b)
|
||||
|
||||
"foo{}".format(1)
|
||||
|
||||
r"foo{}".format(1)
|
||||
|
||||
x = "{a}".format(a=1)
|
||||
|
||||
print("foo {} ".format(x))
|
||||
|
||||
"{a[b]}".format(a=a)
|
||||
|
||||
"{a.a[b]}".format(a=a)
|
||||
|
||||
"{}{{}}{}".format(escaped, y)
|
||||
|
||||
"{}".format(a)
|
||||
|
||||
###
|
||||
# Non-errors
|
||||
###
|
||||
|
||||
# False-negative: RustPython doesn't parse the `\N{snowman}`.
|
||||
"\N{snowman} {}".format(a)
|
||||
|
||||
"{".format(a)
|
||||
|
||||
"}".format(a)
|
||||
|
||||
"{} {}".format(*a)
|
||||
|
||||
"{0} {0}".format(arg)
|
||||
|
||||
"{x} {x}".format(arg)
|
||||
|
||||
"{x.y} {x.z}".format(arg)
|
||||
|
||||
b"{} {}".format(a, b)
|
||||
|
||||
"{:{}}".format(x, y)
|
||||
|
||||
"{}{}".format(a)
|
||||
|
||||
"" "{}".format(a["\\"])
|
||||
|
||||
"{}".format(a["b"])
|
||||
|
||||
r'"\N{snowman} {}".format(a)'
|
||||
|
||||
"{a}" "{b}".format(a=1, b=1)
|
||||
|
||||
|
||||
async def c():
|
||||
return "{}".format(await 3)
|
||||
|
||||
|
||||
async def c():
|
||||
return "{}".format(1 + await 3)
|
||||
67
resources/test/fixtures/pyupgrade/UP033.py
vendored
Normal file
67
resources/test/fixtures/pyupgrade/UP033.py
vendored
Normal file
@@ -0,0 +1,67 @@
|
||||
import functools
|
||||
from functools import lru_cache
|
||||
|
||||
|
||||
@functools.lru_cache(maxsize=None)
|
||||
def fixme():
|
||||
pass
|
||||
|
||||
|
||||
@lru_cache(maxsize=None)
|
||||
def fixme():
|
||||
pass
|
||||
|
||||
|
||||
@other_decorator
|
||||
@functools.lru_cache(maxsize=None)
|
||||
def fixme():
|
||||
pass
|
||||
|
||||
|
||||
@functools.lru_cache(maxsize=None)
|
||||
@other_decorator
|
||||
def fixme():
|
||||
pass
|
||||
|
||||
|
||||
@functools.lru_cache()
|
||||
def ok():
|
||||
pass
|
||||
|
||||
|
||||
@lru_cache()
|
||||
def ok():
|
||||
pass
|
||||
|
||||
|
||||
@functools.lru_cache(maxsize=64)
|
||||
def ok():
|
||||
pass
|
||||
|
||||
|
||||
@lru_cache(maxsize=64)
|
||||
def ok():
|
||||
pass
|
||||
|
||||
|
||||
def user_func():
|
||||
pass
|
||||
|
||||
|
||||
@lru_cache(user_func)
|
||||
def ok():
|
||||
pass
|
||||
|
||||
|
||||
@lru_cache(user_func, maxsize=None)
|
||||
def ok():
|
||||
pass
|
||||
|
||||
|
||||
def lru_cache(maxsize=None):
|
||||
pass
|
||||
|
||||
|
||||
@lru_cache(maxsize=None)
|
||||
def ok():
|
||||
pass
|
||||
@@ -448,7 +448,7 @@
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"definitions": {
|
||||
"BannedApi": {
|
||||
"ApiBan": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"msg"
|
||||
@@ -743,7 +743,7 @@
|
||||
"null"
|
||||
],
|
||||
"additionalProperties": {
|
||||
"$ref": "#/definitions/BannedApi"
|
||||
"$ref": "#/definitions/ApiBan"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -1356,6 +1356,10 @@
|
||||
"ICN0",
|
||||
"ICN00",
|
||||
"ICN001",
|
||||
"INP",
|
||||
"INP0",
|
||||
"INP00",
|
||||
"INP001",
|
||||
"ISC",
|
||||
"ISC0",
|
||||
"ISC00",
|
||||
@@ -1431,6 +1435,7 @@
|
||||
"PIE79",
|
||||
"PIE790",
|
||||
"PIE794",
|
||||
"PIE796",
|
||||
"PIE8",
|
||||
"PIE80",
|
||||
"PIE807",
|
||||
@@ -1686,6 +1691,8 @@
|
||||
"UP029",
|
||||
"UP03",
|
||||
"UP030",
|
||||
"UP032",
|
||||
"UP033",
|
||||
"W",
|
||||
"W2",
|
||||
"W29",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "ruff_cli"
|
||||
version = "0.0.223"
|
||||
version = "0.0.225"
|
||||
authors = ["Charlie Marsh <charlie.r.marsh@gmail.com>"]
|
||||
edition = "2021"
|
||||
rust-version = "1.65.0"
|
||||
|
||||
@@ -114,7 +114,7 @@ pub fn run(
|
||||
.unwrap_or_else(|(path, message)| {
|
||||
if let Some(path) = &path {
|
||||
let settings = resolver.resolve(path, pyproject_strategy);
|
||||
if settings.enabled.contains(&RuleCode::E902) {
|
||||
if settings.rules.enabled(&RuleCode::E902) {
|
||||
Diagnostics::new(vec![Message {
|
||||
kind: IOError(message).into(),
|
||||
location: Location::default(),
|
||||
@@ -296,7 +296,7 @@ pub fn explain(code: &RuleCode, format: SerializationFormat) -> Result<()> {
|
||||
println!(
|
||||
"{} ({}): {}",
|
||||
code.as_ref(),
|
||||
code.origin().title(),
|
||||
code.origin().name(),
|
||||
code.kind().summary()
|
||||
);
|
||||
}
|
||||
@@ -305,7 +305,7 @@ pub fn explain(code: &RuleCode, format: SerializationFormat) -> Result<()> {
|
||||
"{}",
|
||||
serde_json::to_string_pretty(&Explanation {
|
||||
code: code.as_ref(),
|
||||
origin: code.origin().title(),
|
||||
origin: code.origin().name(),
|
||||
summary: &code.kind().summary(),
|
||||
})?
|
||||
);
|
||||
|
||||
@@ -91,6 +91,23 @@ fn resolve(
|
||||
pub fn main() -> Result<ExitCode> {
|
||||
// Extract command-line arguments.
|
||||
let (cli, overrides) = Cli::parse().partition();
|
||||
|
||||
let default_panic_hook = std::panic::take_hook();
|
||||
std::panic::set_hook(Box::new(move |info| {
|
||||
eprintln!(
|
||||
r#"
|
||||
{}: `ruff` crashed. This indicates a bug in `ruff`. If you could open an issue at:
|
||||
|
||||
https://github.com/charliermarsh/ruff/issues/new?title=%5BPanic%5D
|
||||
|
||||
quoting the executed command, along with the relevant file contents and `pyproject.toml` settings,
|
||||
we'd be very appreciative!
|
||||
"#,
|
||||
"error".red().bold(),
|
||||
);
|
||||
default_panic_hook(info);
|
||||
}));
|
||||
|
||||
let log_level = extract_log_level(&cli);
|
||||
set_up_logging(&log_level)?;
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "ruff_dev"
|
||||
version = "0.0.223"
|
||||
version = "0.0.225"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
|
||||
@@ -47,24 +47,37 @@ pub fn main(cli: &Cli) -> Result<()> {
|
||||
for origin in RuleOrigin::iter() {
|
||||
let prefixes = origin.prefixes();
|
||||
let codes_csv: String = prefixes.as_list(", ");
|
||||
table_out.push_str(&format!("### {} ({codes_csv})", origin.title()));
|
||||
table_out.push_str(&format!("### {} ({codes_csv})", origin.name()));
|
||||
table_out.push('\n');
|
||||
table_out.push('\n');
|
||||
|
||||
toc_out.push_str(&format!(
|
||||
" 1. [{} ({})](#{}-{})\n",
|
||||
origin.title(),
|
||||
origin.name(),
|
||||
codes_csv,
|
||||
origin.title().to_lowercase().replace(' ', "-"),
|
||||
origin.name().to_lowercase().replace(' ', "-"),
|
||||
codes_csv.to_lowercase().replace(',', "-").replace(' ', "")
|
||||
));
|
||||
|
||||
if let Some((url, platform)) = origin.url() {
|
||||
if let Some(url) = origin.url() {
|
||||
let host = url
|
||||
.trim_start_matches("https://")
|
||||
.split('/')
|
||||
.next()
|
||||
.unwrap();
|
||||
table_out.push_str(&format!(
|
||||
"For more, see [{}]({}) on {}.",
|
||||
origin.title(),
|
||||
origin.name(),
|
||||
url,
|
||||
platform
|
||||
match host {
|
||||
"pypi.org" => "PyPI",
|
||||
"github.com" => "GitHub",
|
||||
host => panic!(
|
||||
"unexpected host in URL of {}, expected pypi.org or github.com but found \
|
||||
{host}",
|
||||
origin.name()
|
||||
),
|
||||
}
|
||||
));
|
||||
table_out.push('\n');
|
||||
table_out.push('\n');
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "ruff_macros"
|
||||
version = "0.0.223"
|
||||
version = "0.0.225"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
|
||||
25
scripts/benchmarks/README.md
Normal file
25
scripts/benchmarks/README.md
Normal file
@@ -0,0 +1,25 @@
|
||||
# benchmarks
|
||||
|
||||
Utilities for benchmarking Ruff.
|
||||
|
||||
## Getting Started
|
||||
|
||||
Run `./scripts/benchmarks/run.sh` to clone the benchmarking target (CPython).
|
||||
|
||||
If you're looking to benchmark Ruff against other tools, you'll also need to run `poetry
|
||||
install` to create a virtual environment with the required dependencies.
|
||||
|
||||
## Running Benchmarks
|
||||
|
||||
Run `./scripts/benchmarks/run.sh` to run Ruff over the target repo (CPython). The
|
||||
`./scripts/benchmarks` folder contains a few other benchmarks (e.g., `scripts/benchmarks/run_comparisons.sh`
|
||||
compares Ruff to a variety of other tools).
|
||||
|
||||
## Generating Plots
|
||||
|
||||
The Vega specification for the benchmark plot depicted in the root README can be found at
|
||||
`scripts/benchmarks/graph-spec.json`. You can render this JSON spec in the [Vega Editor](https://vega.github.io/editor/#/edited).
|
||||
|
||||
The images seen in the README are generated by exporting the rendered Vega spec as SVG (at around
|
||||
688px wide) and manually bolding the Ruff title and benchmark time. The dark mode variant is
|
||||
generated by changing the fill from `fill="#333333"` to `fill="#C9D1D9"`.
|
||||
1
scripts/benchmarks/dark.svg
Normal file
1
scripts/benchmarks/dark.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 9.0 KiB |
209
scripts/benchmarks/graph-spec.json
Normal file
209
scripts/benchmarks/graph-spec.json
Normal file
@@ -0,0 +1,209 @@
|
||||
{
|
||||
"$schema": "https://vega.github.io/schema/vega-lite/v5.json",
|
||||
"data": {
|
||||
"values": [
|
||||
{
|
||||
"tool": "Ruff",
|
||||
"time": 0.2943,
|
||||
"timeFormat": "0.29s"
|
||||
},
|
||||
{
|
||||
"tool": "Autoflake",
|
||||
"time": 6.175,
|
||||
"timeFormat": "6.18s"
|
||||
},
|
||||
{
|
||||
"tool": "Flake8",
|
||||
"time": 12.26,
|
||||
"timeFormat": "12.26s"
|
||||
},
|
||||
{
|
||||
"tool": "Pyflakes",
|
||||
"time": 15.786,
|
||||
"timeFormat": "15.79s"
|
||||
},
|
||||
{
|
||||
"tool": "Pycodestyle",
|
||||
"time": 46.921,
|
||||
"timeFormat": "46.92s"
|
||||
},
|
||||
{
|
||||
"tool": "Pylint",
|
||||
"time": 62.0,
|
||||
"timeFormat": "> 60s"
|
||||
}
|
||||
]
|
||||
},
|
||||
"config": {
|
||||
"params": [
|
||||
{
|
||||
"name": "defaultFont",
|
||||
"value": "-apple-system,BlinkMacSystemFont,\"Segoe UI\",Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\""
|
||||
},
|
||||
{
|
||||
"name": "titleColor",
|
||||
"value": "#333333"
|
||||
},
|
||||
{
|
||||
"name": "labelColor",
|
||||
"value": "#333333"
|
||||
}
|
||||
],
|
||||
"header": {
|
||||
"labelFont": {
|
||||
"expr": "defaultFont"
|
||||
},
|
||||
"titleFont": {
|
||||
"expr": "defaultFont"
|
||||
},
|
||||
"titleFontWeight": 500
|
||||
},
|
||||
"text": {
|
||||
"font": {
|
||||
"expr": "defaultFont"
|
||||
},
|
||||
"color": {
|
||||
"expr": "labelColor"
|
||||
}
|
||||
},
|
||||
"mark": {
|
||||
"font": {
|
||||
"expr": "defaultFont"
|
||||
},
|
||||
"color": {
|
||||
"expr": "labelColor"
|
||||
}
|
||||
},
|
||||
"title": {
|
||||
"font": {
|
||||
"expr": "defaultFont"
|
||||
},
|
||||
"subtitleFont": {
|
||||
"expr": "defaultFont"
|
||||
},
|
||||
"fontWeight": 500
|
||||
},
|
||||
"axis": {
|
||||
"labelColor": {
|
||||
"expr": "labelColor"
|
||||
},
|
||||
"labelFont": {
|
||||
"expr": "defaultFont"
|
||||
},
|
||||
"titleFont": {
|
||||
"expr": "defaultFont"
|
||||
},
|
||||
"titleFontWeight": 500,
|
||||
"titleColor": {
|
||||
"expr": "titleColor"
|
||||
},
|
||||
"titleFontSize": 12
|
||||
},
|
||||
"legend": {
|
||||
"titleFontWeight": 500,
|
||||
"titleColor": {
|
||||
"expr": "titleColor"
|
||||
},
|
||||
"titleFontSize": 12,
|
||||
"labelColor": {
|
||||
"expr": "labelColor"
|
||||
},
|
||||
"labelFont": {
|
||||
"expr": "defaultFont"
|
||||
},
|
||||
"titleFont": {
|
||||
"expr": "defaultFont"
|
||||
}
|
||||
},
|
||||
"view": {
|
||||
"stroke": null
|
||||
},
|
||||
"background": "transparent"
|
||||
},
|
||||
"background": "transparent",
|
||||
"encoding": {
|
||||
"y": {
|
||||
"field": "tool",
|
||||
"type": "nominal",
|
||||
"axis": {
|
||||
"grid": false,
|
||||
"title": null,
|
||||
"labelFontSize": 12,
|
||||
"ticks": false,
|
||||
"labelPadding": 10,
|
||||
"domain": false
|
||||
},
|
||||
"sort": null
|
||||
},
|
||||
"x": {
|
||||
"field": "time",
|
||||
"type": "quantitative",
|
||||
"axis": {
|
||||
"title": null,
|
||||
"labelExpr": "datum.value + 's'",
|
||||
"tickCount": 3,
|
||||
"tickSize": 0,
|
||||
"labelPadding": 6,
|
||||
"labelAlign": "center",
|
||||
"labelFontSize": 12,
|
||||
"tickColor": "rgba(127,127,127,0.25)",
|
||||
"gridColor": "rgba(127,127,127,0.25)",
|
||||
"domain": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"height": 140,
|
||||
"width": "container",
|
||||
"layer": [
|
||||
{
|
||||
"mark": "bar",
|
||||
"encoding": {
|
||||
"size": {
|
||||
"value": 13
|
||||
},
|
||||
"color": {
|
||||
"value": "#E15759"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"transform": [
|
||||
{
|
||||
"filter": "datum.tool !== 'ruff'"
|
||||
}
|
||||
],
|
||||
"mark": {
|
||||
"type": "text",
|
||||
"align": "left",
|
||||
"baseline": "middle",
|
||||
"dx": 6,
|
||||
"fontSize": 12
|
||||
},
|
||||
"encoding": {
|
||||
"text": {
|
||||
"field": "timeFormat"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"transform": [
|
||||
{
|
||||
"filter": "datum.tool === 'ruff'"
|
||||
}
|
||||
],
|
||||
"mark": {
|
||||
"type": "text",
|
||||
"align": "left",
|
||||
"baseline": "middle",
|
||||
"dx": 6,
|
||||
"fontSize": 12,
|
||||
"fontWeight": "bold"
|
||||
},
|
||||
"encoding": {
|
||||
"text": {
|
||||
"field": "timeFormat"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
1
scripts/benchmarks/light.svg
Normal file
1
scripts/benchmarks/light.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 9.0 KiB |
1005
scripts/benchmarks/poetry.lock
generated
Normal file
1005
scripts/benchmarks/poetry.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
77
scripts/benchmarks/pyproject.toml
Normal file
77
scripts/benchmarks/pyproject.toml
Normal file
@@ -0,0 +1,77 @@
|
||||
[tool.poetry]
|
||||
name = "scripts"
|
||||
version = "0.1.0"
|
||||
description = ""
|
||||
authors = ["Charles Marsh <charlie.r.marsh@gmail.com>"]
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
python = ">=3.10,<3.12"
|
||||
autoflake = "^2.0.0"
|
||||
flake8 = "^6.0.0"
|
||||
pycodestyle = "^2.10.0"
|
||||
pyflakes = "^3.0.1"
|
||||
pylint = "^2.15.10"
|
||||
black = "^22.12.0"
|
||||
isort = "^5.11.4"
|
||||
flake8-2020 = { version = "*", optional = true }
|
||||
flake8-annotations = { version = "*", optional = true }
|
||||
flake8-bandit = { version = "*", optional = true }
|
||||
flake8-blind-except = { version = "*", optional = true }
|
||||
# flake8-boolean-trap = { version = "*", optional = true }
|
||||
flake8-bugbear = { version = "*", optional = true }
|
||||
flake8-builtins = { version = "*", optional = true }
|
||||
flake8-commas = { version = "*", optional = true }
|
||||
flake8-comprehensions = { version = "*", optional = true }
|
||||
flake8-datetimez = { version = "*", optional = true }
|
||||
flake8-debugger = { version = "*", optional = true }
|
||||
flake8-docstrings = { version = "*", optional = true }
|
||||
# flake8-eradicate = { version = "*", optional = true }
|
||||
flake8-errmsg = { version = "*", optional = true }
|
||||
flake8-implicit-str-concat = { version = "*", optional = true }
|
||||
# flake8-import-conventions = { version = "*", optional = true }
|
||||
flake8-isort = { version = "*", optional = true }
|
||||
flake8-pie = { version = "*", optional = true }
|
||||
flake8-print = { version = "*", optional = true }
|
||||
flake8-quotes = { version = "*", optional = true }
|
||||
flake8-return = { version = "*", optional = true }
|
||||
flake8-simplify = { version = "*", optional = true }
|
||||
flake8-super = { version = "*", optional = true }
|
||||
flake8-tidy-imports = { version = "*", optional = true }
|
||||
pandas-vet = { version = "*", optional = true }
|
||||
pep8-naming = { version = "*", optional = true }
|
||||
|
||||
[tool.poetry.dev-dependencies]
|
||||
|
||||
[tool.poetry.extras]
|
||||
plugins = [
|
||||
"flake8-2020",
|
||||
"flake8-annotations",
|
||||
"flake8-bandit",
|
||||
"flake8-blind-except",
|
||||
# "flake8-boolean-trap",
|
||||
"flake8-bugbear",
|
||||
"flake8-builtins",
|
||||
"flake8-commas",
|
||||
"flake8-comprehensions",
|
||||
"flake8-datetimez",
|
||||
"flake8-debugger",
|
||||
"flake8-docstrings",
|
||||
# "flake8-eradicate",
|
||||
"flake8-errmsg",
|
||||
"flake8-implicit-str-concat",
|
||||
# "flake8-import-conventions",
|
||||
"flake8-isort",
|
||||
"flake8-pie",
|
||||
"flake8-print",
|
||||
"flake8-quotes",
|
||||
"flake8-return",
|
||||
"flake8-simplify",
|
||||
"flake8-super",
|
||||
"flake8-tidy-imports",
|
||||
"pandas-vet",
|
||||
"pep8-naming",
|
||||
]
|
||||
|
||||
[build-system]
|
||||
requires = ["poetry-core>=1.0.0"]
|
||||
build-backend = "poetry.core.masonry.api"
|
||||
8
scripts/benchmarks/run.sh
Executable file
8
scripts/benchmarks/run.sh
Executable file
@@ -0,0 +1,8 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
###
|
||||
# Benchmark Ruff on the CPython codebase.
|
||||
###
|
||||
|
||||
cargo build --release && hyperfine --ignore-failure --warmup 10 \
|
||||
"./target/release/ruff ./resources/test/cpython/ --no-cache"
|
||||
26
scripts/benchmarks/run_all.sh
Executable file
26
scripts/benchmarks/run_all.sh
Executable file
@@ -0,0 +1,26 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
###
|
||||
# Benchmark Ruff's performance against a variety of similar tools, suppressing output as much as
|
||||
# possible (so as to reduce I/O overhead).
|
||||
###
|
||||
|
||||
# Note: Flake8's `checker.py` requires the following variant of `mp_run`:
|
||||
# def _mp_run(filename: str) -> tuple[str, Results, dict[str, int]]:
|
||||
# try:
|
||||
# return FileChecker(
|
||||
# filename=filename, plugins=_mp_plugins, options=_mp_options
|
||||
# ).run_checks()
|
||||
# except:
|
||||
# return (filename, [], {
|
||||
# "files": 0,
|
||||
# "logical lines": 0,
|
||||
# "physical lines": 0,
|
||||
# "tokens": 0,
|
||||
# })
|
||||
|
||||
hyperfine --ignore-failure --warmup 5 \
|
||||
"./target/release/ruff ./resources/test/cpython/ --no-cache --silent --select ALL" \
|
||||
"flake8 resources/test/cpython -qq --docstring-convention=all" \
|
||||
"pycodestyle resources/test/cpython -qq" \
|
||||
"pylint resources/test/cpython -j 0 --recursive=y --disable=E,W,C,R"
|
||||
12
scripts/benchmarks/run_comparisons.sh
Executable file
12
scripts/benchmarks/run_comparisons.sh
Executable file
@@ -0,0 +1,12 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
###
|
||||
# Benchmark Ruff's performance against a variety of similar tools.
|
||||
###
|
||||
|
||||
hyperfine --ignore-failure --warmup 5 \
|
||||
"./target/release/ruff ./resources/test/cpython/ --no-cache" \
|
||||
"pyflakes resources/test/cpython" \
|
||||
"autoflake --recursive --expand-star-imports --remove-all-unused-imports --remove-unused-variables --remove-duplicate-keys resources/test/cpython" \
|
||||
"pycodestyle resources/test/cpython" \
|
||||
"flake8 resources/test/cpython"
|
||||
43
scripts/benchmarks/run_plugins.sh
Normal file
43
scripts/benchmarks/run_plugins.sh
Normal file
@@ -0,0 +1,43 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
###
|
||||
# Benchmark the incremental performance of each subsequent plugin.
|
||||
###
|
||||
|
||||
cargo build --release && hyperfine --ignore-failure --warmup 10 \
|
||||
"./target/release/ruff ./resources/test/cpython/ --no-cache --silent" \
|
||||
"./target/release/ruff ./resources/test/cpython/ --no-cache --silent --extend-select C90" \
|
||||
"./target/release/ruff ./resources/test/cpython/ --no-cache --silent --extend-select I" \
|
||||
"./target/release/ruff ./resources/test/cpython/ --no-cache --silent --extend-select D" \
|
||||
"./target/release/ruff ./resources/test/cpython/ --no-cache --silent --extend-select UP" \
|
||||
"./target/release/ruff ./resources/test/cpython/ --no-cache --silent --extend-select N" \
|
||||
"./target/release/ruff ./resources/test/cpython/ --no-cache --silent --extend-select YTT" \
|
||||
"./target/release/ruff ./resources/test/cpython/ --no-cache --silent --extend-select ANN" \
|
||||
"./target/release/ruff ./resources/test/cpython/ --no-cache --silent --extend-select S" \
|
||||
"./target/release/ruff ./resources/test/cpython/ --no-cache --silent --extend-select BLE" \
|
||||
"./target/release/ruff ./resources/test/cpython/ --no-cache --silent --extend-select FBT" \
|
||||
"./target/release/ruff ./resources/test/cpython/ --no-cache --silent --extend-select B" \
|
||||
"./target/release/ruff ./resources/test/cpython/ --no-cache --silent --extend-select A" \
|
||||
"./target/release/ruff ./resources/test/cpython/ --no-cache --silent --extend-select C4" \
|
||||
"./target/release/ruff ./resources/test/cpython/ --no-cache --silent --extend-select T10" \
|
||||
"./target/release/ruff ./resources/test/cpython/ --no-cache --silent --extend-select EM" \
|
||||
"./target/release/ruff ./resources/test/cpython/ --no-cache --silent --extend-select ISC" \
|
||||
"./target/release/ruff ./resources/test/cpython/ --no-cache --silent --extend-select ICN" \
|
||||
"./target/release/ruff ./resources/test/cpython/ --no-cache --silent --extend-select T20" \
|
||||
"./target/release/ruff ./resources/test/cpython/ --no-cache --silent --extend-select PT" \
|
||||
"./target/release/ruff ./resources/test/cpython/ --no-cache --silent --extend-select Q" \
|
||||
"./target/release/ruff ./resources/test/cpython/ --no-cache --silent --extend-select RET" \
|
||||
"./target/release/ruff ./resources/test/cpython/ --no-cache --silent --extend-select SIM" \
|
||||
"./target/release/ruff ./resources/test/cpython/ --no-cache --silent --extend-select TID" \
|
||||
"./target/release/ruff ./resources/test/cpython/ --no-cache --silent --extend-select ARG" \
|
||||
"./target/release/ruff ./resources/test/cpython/ --no-cache --silent --extend-select DTZ" \
|
||||
"./target/release/ruff ./resources/test/cpython/ --no-cache --silent --extend-select ERA" \
|
||||
"./target/release/ruff ./resources/test/cpython/ --no-cache --silent --extend-select PD" \
|
||||
"./target/release/ruff ./resources/test/cpython/ --no-cache --silent --extend-select PGH" \
|
||||
"./target/release/ruff ./resources/test/cpython/ --no-cache --silent --extend-select PLC" \
|
||||
"./target/release/ruff ./resources/test/cpython/ --no-cache --silent --extend-select PLE" \
|
||||
"./target/release/ruff ./resources/test/cpython/ --no-cache --silent --extend-select PLR" \
|
||||
"./target/release/ruff ./resources/test/cpython/ --no-cache --silent --extend-select PLW" \
|
||||
"./target/release/ruff ./resources/test/cpython/ --no-cache --silent --extend-select PIE" \
|
||||
"./target/release/ruff ./resources/test/cpython/ --no-cache --silent --extend-select COM" \
|
||||
"./target/release/ruff ./resources/test/cpython/ --no-cache --silent --extend-select RUF"
|
||||
12
scripts/benchmarks/run_silent.sh
Executable file
12
scripts/benchmarks/run_silent.sh
Executable file
@@ -0,0 +1,12 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
###
|
||||
# Benchmark Ruff's performance against a variety of similar tools, suppressing output as much as
|
||||
# possible (so as to reduce I/O overhead).
|
||||
###
|
||||
|
||||
hyperfine --ignore-failure --warmup 5 \
|
||||
"./target/release/ruff ./resources/test/cpython/ --no-cache --silent" \
|
||||
"pycodestyle resources/test/cpython -qq" \
|
||||
"flake8 resources/test/cpython -qq" \
|
||||
"pylint resources/test/cpython -j 0 --recursive=y --disable=E,W,C,R"
|
||||
7
scripts/benchmarks/setup.sh
Executable file
7
scripts/benchmarks/setup.sh
Executable file
@@ -0,0 +1,7 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
###
|
||||
# Setup the CPython repository to enable benchmarking.
|
||||
###
|
||||
|
||||
git clone --branch 3.10 https://github.com/python/cpython.git resources/test/cpython
|
||||
305
scripts/poetry.lock
generated
305
scripts/poetry.lock
generated
@@ -1,305 +0,0 @@
|
||||
# This file is automatically @generated by Poetry and should not be changed by hand.
|
||||
|
||||
[[package]]
|
||||
name = "astroid"
|
||||
version = "2.12.13"
|
||||
description = "An abstract syntax tree for Python with inference support."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.7.2"
|
||||
files = [
|
||||
{file = "astroid-2.12.13-py3-none-any.whl", hash = "sha256:10e0ad5f7b79c435179d0d0f0df69998c4eef4597534aae44910db060baeb907"},
|
||||
{file = "astroid-2.12.13.tar.gz", hash = "sha256:1493fe8bd3dfd73dc35bd53c9d5b6e49ead98497c47b2307662556a5692d29d7"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
lazy-object-proxy = ">=1.4.0"
|
||||
wrapt = {version = ">=1.11,<2", markers = "python_version < \"3.11\""}
|
||||
|
||||
[[package]]
|
||||
name = "autoflake"
|
||||
version = "1.7.8"
|
||||
description = "Removes unused imports and unused variables"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "autoflake-1.7.8-py3-none-any.whl", hash = "sha256:46373ef69b6714f5064c923bb28bd797c4f8a9497f557d87fc36665c6d956b39"},
|
||||
{file = "autoflake-1.7.8.tar.gz", hash = "sha256:e7e46372dee46fa1c97acf310d99d922b63d369718a270809d7c278d34a194cf"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
pyflakes = ">=1.1.0,<3"
|
||||
tomli = {version = ">=2.0.1", markers = "python_version < \"3.11\""}
|
||||
|
||||
[[package]]
|
||||
name = "colorama"
|
||||
version = "0.4.6"
|
||||
description = "Cross-platform colored terminal text."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
|
||||
files = [
|
||||
{file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"},
|
||||
{file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dill"
|
||||
version = "0.3.6"
|
||||
description = "serialize all of python"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "dill-0.3.6-py3-none-any.whl", hash = "sha256:a07ffd2351b8c678dfc4a856a3005f8067aea51d6ba6c700796a4d9e280f39f0"},
|
||||
{file = "dill-0.3.6.tar.gz", hash = "sha256:e5db55f3687856d8fbdab002ed78544e1c4559a130302693d839dfe8f93f2373"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
graph = ["objgraph (>=1.7.2)"]
|
||||
|
||||
[[package]]
|
||||
name = "flake8"
|
||||
version = "5.0.4"
|
||||
description = "the modular source code checker: pep8 pyflakes and co"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.6.1"
|
||||
files = [
|
||||
{file = "flake8-5.0.4-py2.py3-none-any.whl", hash = "sha256:7a1cf6b73744f5806ab95e526f6f0d8c01c66d7bbe349562d22dfca20610b248"},
|
||||
{file = "flake8-5.0.4.tar.gz", hash = "sha256:6fbe320aad8d6b95cec8b8e47bc933004678dc63095be98528b7bdd2a9f510db"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
mccabe = ">=0.7.0,<0.8.0"
|
||||
pycodestyle = ">=2.9.0,<2.10.0"
|
||||
pyflakes = ">=2.5.0,<2.6.0"
|
||||
|
||||
[[package]]
|
||||
name = "isort"
|
||||
version = "5.11.4"
|
||||
description = "A Python utility / library to sort Python imports."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.7.0"
|
||||
files = [
|
||||
{file = "isort-5.11.4-py3-none-any.whl", hash = "sha256:c033fd0edb91000a7f09527fe5c75321878f98322a77ddcc81adbd83724afb7b"},
|
||||
{file = "isort-5.11.4.tar.gz", hash = "sha256:6db30c5ded9815d813932c04c2f85a360bcdd35fed496f4d8f35495ef0a261b6"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
colors = ["colorama (>=0.4.3,<0.5.0)"]
|
||||
pipfile-deprecated-finder = ["pipreqs", "requirementslib"]
|
||||
plugins = ["setuptools"]
|
||||
requirements-deprecated-finder = ["pip-api", "pipreqs"]
|
||||
|
||||
[[package]]
|
||||
name = "lazy-object-proxy"
|
||||
version = "1.8.0"
|
||||
description = "A fast and thorough lazy object proxy."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "lazy-object-proxy-1.8.0.tar.gz", hash = "sha256:c219a00245af0f6fa4e95901ed28044544f50152840c5b6a3e7b2568db34d156"},
|
||||
{file = "lazy_object_proxy-1.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:4fd031589121ad46e293629b39604031d354043bb5cdf83da4e93c2d7f3389fe"},
|
||||
{file = "lazy_object_proxy-1.8.0-cp310-cp310-win32.whl", hash = "sha256:b70d6e7a332eb0217e7872a73926ad4fdc14f846e85ad6749ad111084e76df25"},
|
||||
{file = "lazy_object_proxy-1.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:eb329f8d8145379bf5dbe722182410fe8863d186e51bf034d2075eb8d85ee25b"},
|
||||
{file = "lazy_object_proxy-1.8.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4e2d9f764f1befd8bdc97673261b8bb888764dfdbd7a4d8f55e4fbcabb8c3fb7"},
|
||||
{file = "lazy_object_proxy-1.8.0-cp311-cp311-win32.whl", hash = "sha256:e20bfa6db17a39c706d24f82df8352488d2943a3b7ce7d4c22579cb89ca8896e"},
|
||||
{file = "lazy_object_proxy-1.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:14010b49a2f56ec4943b6cf925f597b534ee2fe1f0738c84b3bce0c1a11ff10d"},
|
||||
{file = "lazy_object_proxy-1.8.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:6850e4aeca6d0df35bb06e05c8b934ff7c533734eb51d0ceb2d63696f1e6030c"},
|
||||
{file = "lazy_object_proxy-1.8.0-cp37-cp37m-win32.whl", hash = "sha256:5b51d6f3bfeb289dfd4e95de2ecd464cd51982fe6f00e2be1d0bf94864d58acd"},
|
||||
{file = "lazy_object_proxy-1.8.0-cp37-cp37m-win_amd64.whl", hash = "sha256:6f593f26c470a379cf7f5bc6db6b5f1722353e7bf937b8d0d0b3fba911998858"},
|
||||
{file = "lazy_object_proxy-1.8.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0c1c7c0433154bb7c54185714c6929acc0ba04ee1b167314a779b9025517eada"},
|
||||
{file = "lazy_object_proxy-1.8.0-cp38-cp38-win32.whl", hash = "sha256:d176f392dbbdaacccf15919c77f526edf11a34aece58b55ab58539807b85436f"},
|
||||
{file = "lazy_object_proxy-1.8.0-cp38-cp38-win_amd64.whl", hash = "sha256:afcaa24e48bb23b3be31e329deb3f1858f1f1df86aea3d70cb5c8578bfe5261c"},
|
||||
{file = "lazy_object_proxy-1.8.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:71d9ae8a82203511a6f60ca5a1b9f8ad201cac0fc75038b2dc5fa519589c9288"},
|
||||
{file = "lazy_object_proxy-1.8.0-cp39-cp39-win32.whl", hash = "sha256:8f6ce2118a90efa7f62dd38c7dbfffd42f468b180287b748626293bf12ed468f"},
|
||||
{file = "lazy_object_proxy-1.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:eac3a9a5ef13b332c059772fd40b4b1c3d45a3a2b05e33a361dee48e54a4dad0"},
|
||||
{file = "lazy_object_proxy-1.8.0-pp37-pypy37_pp73-any.whl", hash = "sha256:ae032743794fba4d171b5b67310d69176287b5bf82a21f588282406a79498891"},
|
||||
{file = "lazy_object_proxy-1.8.0-pp38-pypy38_pp73-any.whl", hash = "sha256:7e1561626c49cb394268edd00501b289053a652ed762c58e1081224c8d881cec"},
|
||||
{file = "lazy_object_proxy-1.8.0-pp39-pypy39_pp73-any.whl", hash = "sha256:ce58b2b3734c73e68f0e30e4e725264d4d6be95818ec0a0be4bb6bf9a7e79aa8"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mccabe"
|
||||
version = "0.7.0"
|
||||
description = "McCabe checker, plugin for flake8"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
files = [
|
||||
{file = "mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"},
|
||||
{file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "platformdirs"
|
||||
version = "2.6.2"
|
||||
description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "platformdirs-2.6.2-py3-none-any.whl", hash = "sha256:83c8f6d04389165de7c9b6f0c682439697887bca0aa2f1c87ef1826be3584490"},
|
||||
{file = "platformdirs-2.6.2.tar.gz", hash = "sha256:e1fea1fe471b9ff8332e229df3cb7de4f53eeea4998d3b6bfff542115e998bd2"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
docs = ["furo (>=2022.12.7)", "proselint (>=0.13)", "sphinx (>=5.3)", "sphinx-autodoc-typehints (>=1.19.5)"]
|
||||
test = ["appdirs (==1.4.4)", "covdefaults (>=2.2.2)", "pytest (>=7.2)", "pytest-cov (>=4)", "pytest-mock (>=3.10)"]
|
||||
|
||||
[[package]]
|
||||
name = "pycodestyle"
|
||||
version = "2.9.1"
|
||||
description = "Python style guide checker"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
files = [
|
||||
{file = "pycodestyle-2.9.1-py2.py3-none-any.whl", hash = "sha256:d1735fc58b418fd7c5f658d28d943854f8a849b01a5d0a1e6f3f3fdd0166804b"},
|
||||
{file = "pycodestyle-2.9.1.tar.gz", hash = "sha256:2c9607871d58c76354b697b42f5d57e1ada7d261c261efac224b664affdc5785"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pyflakes"
|
||||
version = "2.5.0"
|
||||
description = "passive checker of Python programs"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
files = [
|
||||
{file = "pyflakes-2.5.0-py2.py3-none-any.whl", hash = "sha256:4579f67d887f804e67edb544428f264b7b24f435b263c4614f384135cea553d2"},
|
||||
{file = "pyflakes-2.5.0.tar.gz", hash = "sha256:491feb020dca48ccc562a8c0cbe8df07ee13078df59813b83959cbdada312ea3"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pylint"
|
||||
version = "2.15.9"
|
||||
description = "python code static checker"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.7.2"
|
||||
files = [
|
||||
{file = "pylint-2.15.9-py3-none-any.whl", hash = "sha256:349c8cd36aede4d50a0754a8c0218b43323d13d5d88f4b2952ddfe3e169681eb"},
|
||||
{file = "pylint-2.15.9.tar.gz", hash = "sha256:18783cca3cfee5b83c6c5d10b3cdb66c6594520ffae61890858fe8d932e1c6b4"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
astroid = ">=2.12.13,<=2.14.0-dev0"
|
||||
colorama = {version = ">=0.4.5", markers = "sys_platform == \"win32\""}
|
||||
dill = {version = ">=0.2", markers = "python_version < \"3.11\""}
|
||||
isort = ">=4.2.5,<6"
|
||||
mccabe = ">=0.6,<0.8"
|
||||
platformdirs = ">=2.2.0"
|
||||
tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""}
|
||||
tomlkit = ">=0.10.1"
|
||||
|
||||
[package.extras]
|
||||
spelling = ["pyenchant (>=3.2,<4.0)"]
|
||||
testutils = ["gitpython (>3)"]
|
||||
|
||||
[[package]]
|
||||
name = "tomli"
|
||||
version = "2.0.1"
|
||||
description = "A lil' TOML parser"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"},
|
||||
{file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tomlkit"
|
||||
version = "0.11.6"
|
||||
description = "Style preserving TOML library"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
files = [
|
||||
{file = "tomlkit-0.11.6-py3-none-any.whl", hash = "sha256:07de26b0d8cfc18f871aec595fda24d95b08fef89d147caa861939f37230bf4b"},
|
||||
{file = "tomlkit-0.11.6.tar.gz", hash = "sha256:71b952e5721688937fb02cf9d354dbcf0785066149d2855e44531ebdd2b65d73"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wrapt"
|
||||
version = "1.14.1"
|
||||
description = "Module for decorators, wrappers and monkey patching."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7"
|
||||
files = [
|
||||
{file = "wrapt-1.14.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:1b376b3f4896e7930f1f772ac4b064ac12598d1c38d04907e696cc4d794b43d3"},
|
||||
{file = "wrapt-1.14.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:903500616422a40a98a5a3c4ff4ed9d0066f3b4c951fa286018ecdf0750194ef"},
|
||||
{file = "wrapt-1.14.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:5a9a0d155deafd9448baff28c08e150d9b24ff010e899311ddd63c45c2445e28"},
|
||||
{file = "wrapt-1.14.1-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:ddaea91abf8b0d13443f6dac52e89051a5063c7d014710dcb4d4abb2ff811a59"},
|
||||
{file = "wrapt-1.14.1-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:36f582d0c6bc99d5f39cd3ac2a9062e57f3cf606ade29a0a0d6b323462f4dd87"},
|
||||
{file = "wrapt-1.14.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:7ef58fb89674095bfc57c4069e95d7a31cfdc0939e2a579882ac7d55aadfd2a1"},
|
||||
{file = "wrapt-1.14.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:e2f83e18fe2f4c9e7db597e988f72712c0c3676d337d8b101f6758107c42425b"},
|
||||
{file = "wrapt-1.14.1-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:ee2b1b1769f6707a8a445162ea16dddf74285c3964f605877a20e38545c3c462"},
|
||||
{file = "wrapt-1.14.1-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:833b58d5d0b7e5b9832869f039203389ac7cbf01765639c7309fd50ef619e0b1"},
|
||||
{file = "wrapt-1.14.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:80bb5c256f1415f747011dc3604b59bc1f91c6e7150bd7db03b19170ee06b320"},
|
||||
{file = "wrapt-1.14.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:07f7a7d0f388028b2df1d916e94bbb40624c59b48ecc6cbc232546706fac74c2"},
|
||||
{file = "wrapt-1.14.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:02b41b633c6261feff8ddd8d11c711df6842aba629fdd3da10249a53211a72c4"},
|
||||
{file = "wrapt-1.14.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2fe803deacd09a233e4762a1adcea5db5d31e6be577a43352936179d14d90069"},
|
||||
{file = "wrapt-1.14.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:257fd78c513e0fb5cdbe058c27a0624c9884e735bbd131935fd49e9fe719d310"},
|
||||
{file = "wrapt-1.14.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:4fcc4649dc762cddacd193e6b55bc02edca674067f5f98166d7713b193932b7f"},
|
||||
{file = "wrapt-1.14.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:11871514607b15cfeb87c547a49bca19fde402f32e2b1c24a632506c0a756656"},
|
||||
{file = "wrapt-1.14.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8ad85f7f4e20964db4daadcab70b47ab05c7c1cf2a7c1e51087bfaa83831854c"},
|
||||
{file = "wrapt-1.14.1-cp310-cp310-win32.whl", hash = "sha256:a9a52172be0b5aae932bef82a79ec0a0ce87288c7d132946d645eba03f0ad8a8"},
|
||||
{file = "wrapt-1.14.1-cp310-cp310-win_amd64.whl", hash = "sha256:6d323e1554b3d22cfc03cd3243b5bb815a51f5249fdcbb86fda4bf62bab9e164"},
|
||||
{file = "wrapt-1.14.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:43ca3bbbe97af00f49efb06e352eae40434ca9d915906f77def219b88e85d907"},
|
||||
{file = "wrapt-1.14.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:6b1a564e6cb69922c7fe3a678b9f9a3c54e72b469875aa8018f18b4d1dd1adf3"},
|
||||
{file = "wrapt-1.14.1-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:00b6d4ea20a906c0ca56d84f93065b398ab74b927a7a3dbd470f6fc503f95dc3"},
|
||||
{file = "wrapt-1.14.1-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:a85d2b46be66a71bedde836d9e41859879cc54a2a04fad1191eb50c2066f6e9d"},
|
||||
{file = "wrapt-1.14.1-cp35-cp35m-win32.whl", hash = "sha256:dbcda74c67263139358f4d188ae5faae95c30929281bc6866d00573783c422b7"},
|
||||
{file = "wrapt-1.14.1-cp35-cp35m-win_amd64.whl", hash = "sha256:b21bb4c09ffabfa0e85e3a6b623e19b80e7acd709b9f91452b8297ace2a8ab00"},
|
||||
{file = "wrapt-1.14.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:9e0fd32e0148dd5dea6af5fee42beb949098564cc23211a88d799e434255a1f4"},
|
||||
{file = "wrapt-1.14.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9736af4641846491aedb3c3f56b9bc5568d92b0692303b5a305301a95dfd38b1"},
|
||||
{file = "wrapt-1.14.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5b02d65b9ccf0ef6c34cba6cf5bf2aab1bb2f49c6090bafeecc9cd81ad4ea1c1"},
|
||||
{file = "wrapt-1.14.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21ac0156c4b089b330b7666db40feee30a5d52634cc4560e1905d6529a3897ff"},
|
||||
{file = "wrapt-1.14.1-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:9f3e6f9e05148ff90002b884fbc2a86bd303ae847e472f44ecc06c2cd2fcdb2d"},
|
||||
{file = "wrapt-1.14.1-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:6e743de5e9c3d1b7185870f480587b75b1cb604832e380d64f9504a0535912d1"},
|
||||
{file = "wrapt-1.14.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:d79d7d5dc8a32b7093e81e97dad755127ff77bcc899e845f41bf71747af0c569"},
|
||||
{file = "wrapt-1.14.1-cp36-cp36m-win32.whl", hash = "sha256:81b19725065dcb43df02b37e03278c011a09e49757287dca60c5aecdd5a0b8ed"},
|
||||
{file = "wrapt-1.14.1-cp36-cp36m-win_amd64.whl", hash = "sha256:b014c23646a467558be7da3d6b9fa409b2c567d2110599b7cf9a0c5992b3b471"},
|
||||
{file = "wrapt-1.14.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:88bd7b6bd70a5b6803c1abf6bca012f7ed963e58c68d76ee20b9d751c74a3248"},
|
||||
{file = "wrapt-1.14.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b5901a312f4d14c59918c221323068fad0540e34324925c8475263841dbdfe68"},
|
||||
{file = "wrapt-1.14.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d77c85fedff92cf788face9bfa3ebaa364448ebb1d765302e9af11bf449ca36d"},
|
||||
{file = "wrapt-1.14.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d649d616e5c6a678b26d15ece345354f7c2286acd6db868e65fcc5ff7c24a77"},
|
||||
{file = "wrapt-1.14.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:7d2872609603cb35ca513d7404a94d6d608fc13211563571117046c9d2bcc3d7"},
|
||||
{file = "wrapt-1.14.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:ee6acae74a2b91865910eef5e7de37dc6895ad96fa23603d1d27ea69df545015"},
|
||||
{file = "wrapt-1.14.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:2b39d38039a1fdad98c87279b48bc5dce2c0ca0d73483b12cb72aa9609278e8a"},
|
||||
{file = "wrapt-1.14.1-cp37-cp37m-win32.whl", hash = "sha256:60db23fa423575eeb65ea430cee741acb7c26a1365d103f7b0f6ec412b893853"},
|
||||
{file = "wrapt-1.14.1-cp37-cp37m-win_amd64.whl", hash = "sha256:709fe01086a55cf79d20f741f39325018f4df051ef39fe921b1ebe780a66184c"},
|
||||
{file = "wrapt-1.14.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8c0ce1e99116d5ab21355d8ebe53d9460366704ea38ae4d9f6933188f327b456"},
|
||||
{file = "wrapt-1.14.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:e3fb1677c720409d5f671e39bac6c9e0e422584e5f518bfd50aa4cbbea02433f"},
|
||||
{file = "wrapt-1.14.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:642c2e7a804fcf18c222e1060df25fc210b9c58db7c91416fb055897fc27e8cc"},
|
||||
{file = "wrapt-1.14.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7b7c050ae976e286906dd3f26009e117eb000fb2cf3533398c5ad9ccc86867b1"},
|
||||
{file = "wrapt-1.14.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ef3f72c9666bba2bab70d2a8b79f2c6d2c1a42a7f7e2b0ec83bb2f9e383950af"},
|
||||
{file = "wrapt-1.14.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:01c205616a89d09827986bc4e859bcabd64f5a0662a7fe95e0d359424e0e071b"},
|
||||
{file = "wrapt-1.14.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:5a0f54ce2c092aaf439813735584b9537cad479575a09892b8352fea5e988dc0"},
|
||||
{file = "wrapt-1.14.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:2cf71233a0ed05ccdabe209c606fe0bac7379fdcf687f39b944420d2a09fdb57"},
|
||||
{file = "wrapt-1.14.1-cp38-cp38-win32.whl", hash = "sha256:aa31fdcc33fef9eb2552cbcbfee7773d5a6792c137b359e82879c101e98584c5"},
|
||||
{file = "wrapt-1.14.1-cp38-cp38-win_amd64.whl", hash = "sha256:d1967f46ea8f2db647c786e78d8cc7e4313dbd1b0aca360592d8027b8508e24d"},
|
||||
{file = "wrapt-1.14.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3232822c7d98d23895ccc443bbdf57c7412c5a65996c30442ebe6ed3df335383"},
|
||||
{file = "wrapt-1.14.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:988635d122aaf2bdcef9e795435662bcd65b02f4f4c1ae37fbee7401c440b3a7"},
|
||||
{file = "wrapt-1.14.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cca3c2cdadb362116235fdbd411735de4328c61425b0aa9f872fd76d02c4e86"},
|
||||
{file = "wrapt-1.14.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d52a25136894c63de15a35bc0bdc5adb4b0e173b9c0d07a2be9d3ca64a332735"},
|
||||
{file = "wrapt-1.14.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40e7bc81c9e2b2734ea4bc1aceb8a8f0ceaac7c5299bc5d69e37c44d9081d43b"},
|
||||
{file = "wrapt-1.14.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b9b7a708dd92306328117d8c4b62e2194d00c365f18eff11a9b53c6f923b01e3"},
|
||||
{file = "wrapt-1.14.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:6a9a25751acb379b466ff6be78a315e2b439d4c94c1e99cb7266d40a537995d3"},
|
||||
{file = "wrapt-1.14.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:34aa51c45f28ba7f12accd624225e2b1e5a3a45206aa191f6f9aac931d9d56fe"},
|
||||
{file = "wrapt-1.14.1-cp39-cp39-win32.whl", hash = "sha256:dee0ce50c6a2dd9056c20db781e9c1cfd33e77d2d569f5d1d9321c641bb903d5"},
|
||||
{file = "wrapt-1.14.1-cp39-cp39-win_amd64.whl", hash = "sha256:dee60e1de1898bde3b238f18340eec6148986da0455d8ba7848d50470a7a32fb"},
|
||||
{file = "wrapt-1.14.1.tar.gz", hash = "sha256:380a85cf89e0e69b7cfbe2ea9f765f004ff419f34194018a6827ac0e3edfed4d"},
|
||||
]
|
||||
|
||||
[metadata]
|
||||
lock-version = "2.0"
|
||||
python-versions = ">=3.10,<3.11"
|
||||
content-hash = "959633dfe6335ab3f943a95c5fdd12ff1bb66cd03c5917704f10ae38d3a5009c"
|
||||
@@ -1,27 +0,0 @@
|
||||
[tool.black]
|
||||
line-length = 120
|
||||
|
||||
[tool.ruff]
|
||||
line-length = 120
|
||||
select = ["E", "F", "W", "I", "C", "RET", "ANN", "UP"]
|
||||
target-version = "py310"
|
||||
|
||||
[tool.poetry]
|
||||
name = "scripts"
|
||||
version = "0.1.0"
|
||||
description = ""
|
||||
authors = ["Charles Marsh <charlie.r.marsh@gmail.com>"]
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
python = ">=3.10,<3.11"
|
||||
autoflake = "^1.4"
|
||||
flake8 = "^5.0.4"
|
||||
pycodestyle = "^2.9.1"
|
||||
pyflakes = "^2.5.0"
|
||||
pylint = "^2.15.0"
|
||||
|
||||
[tool.poetry.dev-dependencies]
|
||||
|
||||
[build-system]
|
||||
requires = ["poetry-core>=1.0.0"]
|
||||
build-backend = "poetry.core.masonry.api"
|
||||
@@ -1,29 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Wrapper around Flake8 to enable multiprocessing on all operating systems.
|
||||
|
||||
As of Python 3.8, macOS's default "start method" for multiprocessing is `spawn`. Flake8
|
||||
requires a "start method" of `fork`, and disables multiprocessing if it detects `spawn`
|
||||
or some other "start method". This script enables the `fork` start method before passing
|
||||
along any command-line arguments to `flake8`.
|
||||
|
||||
This has never caused me any problems, but note that they disabled this for a reason:
|
||||
Flake8's plugin interface doesn't work with `spawn`, and the maintainer says that `fork`
|
||||
is "pretty broken" on macOS.
|
||||
|
||||
See:
|
||||
|
||||
- https://github.com/pycqa/flake8/issues/955
|
||||
- https://github.com/PyCQA/flake8/issues/1337
|
||||
- https://github.com/PyCQA/flake8/issues/342
|
||||
- https://github.com/PyCQA/flake8/pull/1621
|
||||
|
||||
Example usage: python -m run_flake8 --select=E501 .
|
||||
"""
|
||||
import multiprocessing
|
||||
import sys
|
||||
|
||||
from flake8.main import cli
|
||||
|
||||
if __name__ == "__main__":
|
||||
multiprocessing.set_start_method("fork", force=True)
|
||||
cli.main(sys.argv[1:])
|
||||
@@ -94,6 +94,45 @@ pub fn contains_call_path(checker: &Checker, expr: &Expr, target: &[&str]) -> bo
|
||||
})
|
||||
}
|
||||
|
||||
/// Return `true` if the `Expr` contains an expression that appears to include a
|
||||
/// side-effect (like a function call).
|
||||
pub fn contains_effect(checker: &Checker, expr: &Expr) -> bool {
|
||||
any_over_expr(expr, &|expr| {
|
||||
// Accept empty initializers.
|
||||
if let ExprKind::Call {
|
||||
func,
|
||||
args,
|
||||
keywords,
|
||||
} = &expr.node
|
||||
{
|
||||
if args.is_empty() && keywords.is_empty() {
|
||||
if let ExprKind::Name { id, .. } = &func.node {
|
||||
let is_empty_initializer = (id == "set"
|
||||
|| id == "list"
|
||||
|| id == "tuple"
|
||||
|| id == "dict"
|
||||
|| id == "frozenset")
|
||||
&& checker.is_builtin(id);
|
||||
return !is_empty_initializer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise, avoid all complex expressions.
|
||||
matches!(
|
||||
expr.node,
|
||||
ExprKind::Call { .. }
|
||||
| ExprKind::Await { .. }
|
||||
| ExprKind::GeneratorExp { .. }
|
||||
| ExprKind::ListComp { .. }
|
||||
| ExprKind::SetComp { .. }
|
||||
| ExprKind::DictComp { .. }
|
||||
| ExprKind::Yield { .. }
|
||||
| ExprKind::YieldFrom { .. }
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
/// Call `func` over every `Expr` in `expr`, returning `true` if any expression
|
||||
/// returns `true`..
|
||||
pub fn any_over_expr<F>(expr: &Expr, func: &F) -> bool
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
18
src/checkers/filesystem.rs
Normal file
18
src/checkers/filesystem.rs
Normal file
@@ -0,0 +1,18 @@
|
||||
use std::path::Path;
|
||||
|
||||
use crate::registry::{Diagnostic, RuleCode};
|
||||
use crate::rules::flake8_no_pep420::rules::implicit_namespace_package;
|
||||
use crate::settings::Settings;
|
||||
|
||||
pub fn check_file_path(path: &Path, settings: &Settings) -> Vec<Diagnostic> {
|
||||
let mut diagnostics: Vec<Diagnostic> = vec![];
|
||||
|
||||
// flake8-no-pep420
|
||||
if settings.rules.enabled(&RuleCode::INP001) {
|
||||
if let Some(diagnostic) = implicit_namespace_package(path) {
|
||||
diagnostics.push(diagnostic);
|
||||
}
|
||||
}
|
||||
|
||||
diagnostics
|
||||
}
|
||||
@@ -36,7 +36,7 @@ pub fn check_imports(
|
||||
|
||||
// Enforce import rules.
|
||||
let mut diagnostics = vec![];
|
||||
if settings.enabled.contains(&RuleCode::I001) {
|
||||
if settings.rules.enabled(&RuleCode::I001) {
|
||||
for block in &blocks {
|
||||
if !block.imports.is_empty() {
|
||||
if let Some(diagnostic) = isort::rules::organize_imports(
|
||||
@@ -47,7 +47,7 @@ pub fn check_imports(
|
||||
}
|
||||
}
|
||||
}
|
||||
if settings.enabled.contains(&RuleCode::I002) {
|
||||
if settings.rules.enabled(&RuleCode::I002) {
|
||||
diagnostics.extend(isort::rules::add_required_imports(
|
||||
&blocks, python_ast, locator, settings, autofix,
|
||||
));
|
||||
|
||||
@@ -17,12 +17,12 @@ pub fn check_lines(
|
||||
) -> Vec<Diagnostic> {
|
||||
let mut diagnostics: Vec<Diagnostic> = vec![];
|
||||
|
||||
let enforce_blanket_noqa = settings.enabled.contains(&RuleCode::PGH004);
|
||||
let enforce_blanket_type_ignore = settings.enabled.contains(&RuleCode::PGH003);
|
||||
let enforce_doc_line_too_long = settings.enabled.contains(&RuleCode::W505);
|
||||
let enforce_line_too_long = settings.enabled.contains(&RuleCode::E501);
|
||||
let enforce_no_newline_at_end_of_file = settings.enabled.contains(&RuleCode::W292);
|
||||
let enforce_unnecessary_coding_comment = settings.enabled.contains(&RuleCode::UP009);
|
||||
let enforce_blanket_noqa = settings.rules.enabled(&RuleCode::PGH004);
|
||||
let enforce_blanket_type_ignore = settings.rules.enabled(&RuleCode::PGH003);
|
||||
let enforce_doc_line_too_long = settings.rules.enabled(&RuleCode::W505);
|
||||
let enforce_line_too_long = settings.rules.enabled(&RuleCode::E501);
|
||||
let enforce_no_newline_at_end_of_file = settings.rules.enabled(&RuleCode::W292);
|
||||
let enforce_unnecessary_coding_comment = settings.rules.enabled(&RuleCode::UP009);
|
||||
|
||||
let mut commented_lines_iter = commented_lines.iter().peekable();
|
||||
let mut doc_lines_iter = doc_lines.iter().peekable();
|
||||
@@ -37,7 +37,7 @@ pub fn check_lines(
|
||||
index,
|
||||
line,
|
||||
matches!(autofix, flags::Autofix::Enabled)
|
||||
&& settings.fixable.contains(&RuleCode::UP009),
|
||||
&& settings.rules.should_fix(&RuleCode::UP009),
|
||||
) {
|
||||
diagnostics.push(diagnostic);
|
||||
}
|
||||
@@ -79,7 +79,7 @@ pub fn check_lines(
|
||||
if let Some(diagnostic) = no_newline_at_end_of_file(
|
||||
contents,
|
||||
matches!(autofix, flags::Autofix::Enabled)
|
||||
&& settings.fixable.contains(&RuleCode::W292),
|
||||
&& settings.rules.should_fix(&RuleCode::W292),
|
||||
) {
|
||||
diagnostics.push(diagnostic);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
pub mod ast;
|
||||
pub mod filesystem;
|
||||
pub mod imports;
|
||||
pub mod lines;
|
||||
pub mod noqa;
|
||||
|
||||
@@ -24,7 +24,7 @@ pub fn check_noqa(
|
||||
let mut noqa_directives: IntMap<usize, (Directive, Vec<&str>)> = IntMap::default();
|
||||
let mut ignored = vec![];
|
||||
|
||||
let enforce_noqa = settings.enabled.contains(&RuleCode::RUF100);
|
||||
let enforce_noqa = settings.rules.enabled(&RuleCode::RUF100);
|
||||
|
||||
let lines: Vec<&str> = contents.lines().collect();
|
||||
for lineno in commented_lines {
|
||||
@@ -108,7 +108,7 @@ pub fn check_noqa(
|
||||
Range::new(Location::new(row + 1, start), Location::new(row + 1, end)),
|
||||
);
|
||||
if matches!(autofix, flags::Autofix::Enabled)
|
||||
&& settings.fixable.contains(diagnostic.kind.code())
|
||||
&& settings.rules.should_fix(diagnostic.kind.code())
|
||||
{
|
||||
diagnostic.amend(Fix::deletion(
|
||||
Location::new(row + 1, start - spaces),
|
||||
@@ -135,7 +135,7 @@ pub fn check_noqa(
|
||||
valid_codes.push(code);
|
||||
} else {
|
||||
if let Ok(rule_code) = RuleCode::from_str(code) {
|
||||
if settings.enabled.contains(&rule_code) {
|
||||
if settings.rules.enabled(&rule_code) {
|
||||
unmatched_codes.push(code);
|
||||
} else {
|
||||
disabled_codes.push(code);
|
||||
@@ -172,7 +172,7 @@ pub fn check_noqa(
|
||||
Range::new(Location::new(row + 1, start), Location::new(row + 1, end)),
|
||||
);
|
||||
if matches!(autofix, flags::Autofix::Enabled)
|
||||
&& settings.fixable.contains(diagnostic.kind.code())
|
||||
&& settings.rules.should_fix(diagnostic.kind.code())
|
||||
{
|
||||
if valid_codes.is_empty() {
|
||||
diagnostic.amend(Fix::deletion(
|
||||
|
||||
@@ -19,20 +19,20 @@ pub fn check_tokens(
|
||||
) -> Vec<Diagnostic> {
|
||||
let mut diagnostics: Vec<Diagnostic> = vec![];
|
||||
|
||||
let enforce_ambiguous_unicode_character = settings.enabled.contains(&RuleCode::RUF001)
|
||||
|| settings.enabled.contains(&RuleCode::RUF002)
|
||||
|| settings.enabled.contains(&RuleCode::RUF003);
|
||||
let enforce_quotes = settings.enabled.contains(&RuleCode::Q000)
|
||||
|| settings.enabled.contains(&RuleCode::Q001)
|
||||
|| settings.enabled.contains(&RuleCode::Q002)
|
||||
|| settings.enabled.contains(&RuleCode::Q003);
|
||||
let enforce_commented_out_code = settings.enabled.contains(&RuleCode::ERA001);
|
||||
let enforce_invalid_escape_sequence = settings.enabled.contains(&RuleCode::W605);
|
||||
let enforce_implicit_string_concatenation = settings.enabled.contains(&RuleCode::ISC001)
|
||||
|| settings.enabled.contains(&RuleCode::ISC002);
|
||||
let enforce_trailing_comma = settings.enabled.contains(&RuleCode::COM812)
|
||||
|| settings.enabled.contains(&RuleCode::COM818)
|
||||
|| settings.enabled.contains(&RuleCode::COM819);
|
||||
let enforce_ambiguous_unicode_character = settings.rules.enabled(&RuleCode::RUF001)
|
||||
|| settings.rules.enabled(&RuleCode::RUF002)
|
||||
|| settings.rules.enabled(&RuleCode::RUF003);
|
||||
let enforce_quotes = settings.rules.enabled(&RuleCode::Q000)
|
||||
|| settings.rules.enabled(&RuleCode::Q001)
|
||||
|| settings.rules.enabled(&RuleCode::Q002)
|
||||
|| settings.rules.enabled(&RuleCode::Q003);
|
||||
let enforce_commented_out_code = settings.rules.enabled(&RuleCode::ERA001);
|
||||
let enforce_invalid_escape_sequence = settings.rules.enabled(&RuleCode::W605);
|
||||
let enforce_implicit_string_concatenation =
|
||||
settings.rules.enabled(&RuleCode::ISC001) || settings.rules.enabled(&RuleCode::ISC002);
|
||||
let enforce_trailing_comma = settings.rules.enabled(&RuleCode::COM812)
|
||||
|| settings.rules.enabled(&RuleCode::COM818)
|
||||
|| settings.rules.enabled(&RuleCode::COM819);
|
||||
|
||||
let mut state_machine = StateMachine::default();
|
||||
for &(start, ref tok, end) in tokens.iter().flatten() {
|
||||
@@ -75,7 +75,7 @@ pub fn check_tokens(
|
||||
settings,
|
||||
autofix,
|
||||
) {
|
||||
if settings.enabled.contains(diagnostic.kind.code()) {
|
||||
if settings.rules.enabled(diagnostic.kind.code()) {
|
||||
diagnostics.push(diagnostic);
|
||||
}
|
||||
}
|
||||
@@ -101,7 +101,7 @@ pub fn check_tokens(
|
||||
start,
|
||||
end,
|
||||
matches!(autofix, flags::Autofix::Enabled)
|
||||
&& settings.fixable.contains(&RuleCode::W605),
|
||||
&& settings.rules.should_fix(&RuleCode::W605),
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -112,16 +112,16 @@ pub fn check_tokens(
|
||||
diagnostics.extend(
|
||||
flake8_implicit_str_concat::rules::implicit(tokens)
|
||||
.into_iter()
|
||||
.filter(|diagnostic| settings.enabled.contains(diagnostic.kind.code())),
|
||||
.filter(|diagnostic| settings.rules.enabled(diagnostic.kind.code())),
|
||||
);
|
||||
}
|
||||
|
||||
// COM812, COM818, COM819
|
||||
if enforce_trailing_comma {
|
||||
diagnostics.extend(
|
||||
flake8_commas::rules::trailing_commas(tokens, locator)
|
||||
flake8_commas::rules::trailing_commas(tokens, settings, autofix)
|
||||
.into_iter()
|
||||
.filter(|diagnostic| settings.enabled.contains(diagnostic.kind.code())),
|
||||
.filter(|diagnostic| settings.rules.enabled(diagnostic.kind.code())),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -18,8 +18,8 @@ bitflags! {
|
||||
impl Flags {
|
||||
pub fn from_settings(settings: &Settings) -> Self {
|
||||
if settings
|
||||
.enabled
|
||||
.iter()
|
||||
.rules
|
||||
.iter_enabled()
|
||||
.any(|rule_code| matches!(rule_code.lint_source(), LintSource::Imports))
|
||||
{
|
||||
Flags::NOQA | Flags::ISORT
|
||||
|
||||
@@ -7,3 +7,7 @@ pub const TRIPLE_QUOTE_PREFIXES: &[&str] = &[
|
||||
pub const SINGLE_QUOTE_PREFIXES: &[&str] = &[
|
||||
"u\"", "u'", "r\"", "r'", "u\"", "u'", "r\"", "r'", "U\"", "U'", "R\"", "R'", "\"", "'",
|
||||
];
|
||||
|
||||
pub const TRIPLE_QUOTE_SUFFIXES: &[&str] = &["\"\"\"", "'''"];
|
||||
|
||||
pub const SINGLE_QUOTE_SUFFIXES: &[&str] = &["\"", "'"];
|
||||
|
||||
@@ -11,7 +11,7 @@ use crate::rules::flake8_pytest_style::types::{
|
||||
ParametrizeNameType, ParametrizeValuesRowType, ParametrizeValuesType,
|
||||
};
|
||||
use crate::rules::flake8_quotes::settings::Quote;
|
||||
use crate::rules::flake8_tidy_imports::settings::Strictness;
|
||||
use crate::rules::flake8_tidy_imports::relative_imports::Strictness;
|
||||
use crate::rules::pydocstyle::settings::Convention;
|
||||
use crate::rules::{
|
||||
flake8_annotations, flake8_bugbear, flake8_errmsg, flake8_pytest_style, flake8_quotes,
|
||||
@@ -93,7 +93,7 @@ pub fn convert(
|
||||
let mut flake8_errmsg = flake8_errmsg::settings::Options::default();
|
||||
let mut flake8_pytest_style = flake8_pytest_style::settings::Options::default();
|
||||
let mut flake8_quotes = flake8_quotes::settings::Options::default();
|
||||
let mut flake8_tidy_imports = flake8_tidy_imports::settings::Options::default();
|
||||
let mut flake8_tidy_imports = flake8_tidy_imports::options::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();
|
||||
@@ -354,7 +354,7 @@ pub fn convert(
|
||||
if flake8_quotes != flake8_quotes::settings::Options::default() {
|
||||
options.flake8_quotes = Some(flake8_quotes);
|
||||
}
|
||||
if flake8_tidy_imports != flake8_tidy_imports::settings::Options::default() {
|
||||
if flake8_tidy_imports != flake8_tidy_imports::options::Options::default() {
|
||||
options.flake8_tidy_imports = Some(flake8_tidy_imports);
|
||||
}
|
||||
if mccabe != mccabe::settings::Options::default() {
|
||||
|
||||
10
src/fs.rs
10
src/fs.rs
@@ -4,11 +4,11 @@ use std::io::{BufReader, Read};
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use anyhow::{anyhow, Result};
|
||||
use globset::GlobMatcher;
|
||||
use path_absolutize::{path_dedot, Absolutize};
|
||||
use rustc_hash::FxHashSet;
|
||||
|
||||
use crate::registry::RuleCode;
|
||||
use crate::settings::hashable::{HashableGlobMatcher, HashableHashSet};
|
||||
|
||||
/// Extract the absolute path and basename (as strings) from a Path.
|
||||
pub fn extract_path_names(path: &Path) -> Result<(&str, &str)> {
|
||||
@@ -26,7 +26,11 @@ pub fn extract_path_names(path: &Path) -> Result<(&str, &str)> {
|
||||
/// Create a set with codes matching the pattern/code pairs.
|
||||
pub(crate) fn ignores_from_path<'a>(
|
||||
path: &Path,
|
||||
pattern_code_pairs: &'a [(GlobMatcher, GlobMatcher, FxHashSet<RuleCode>)],
|
||||
pattern_code_pairs: &'a [(
|
||||
HashableGlobMatcher,
|
||||
HashableGlobMatcher,
|
||||
HashableHashSet<RuleCode>,
|
||||
)],
|
||||
) -> Result<FxHashSet<&'a RuleCode>> {
|
||||
let (file_path, file_basename) = extract_path_names(path)?;
|
||||
Ok(pattern_code_pairs
|
||||
@@ -34,7 +38,7 @@ pub(crate) fn ignores_from_path<'a>(
|
||||
.filter(|(absolute, basename, _)| {
|
||||
basename.is_match(file_basename) || absolute.is_match(file_path)
|
||||
})
|
||||
.flat_map(|(_, _, codes)| codes)
|
||||
.flat_map(|(_, _, codes)| codes.iter())
|
||||
.collect())
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ use wasm_bindgen::prelude::*;
|
||||
|
||||
use crate::directives;
|
||||
use crate::linter::check_path;
|
||||
use crate::registry::{RuleCode, RuleCodePrefix};
|
||||
use crate::registry::RuleCode;
|
||||
use crate::rules::{
|
||||
flake8_annotations, flake8_bandit, flake8_bugbear, flake8_errmsg, flake8_import_conventions,
|
||||
flake8_pytest_style, flake8_quotes, flake8_tidy_imports, flake8_unused_arguments, isort,
|
||||
@@ -16,8 +16,7 @@ use crate::rules::{
|
||||
use crate::rustpython_helpers::tokenize;
|
||||
use crate::settings::configuration::Configuration;
|
||||
use crate::settings::options::Options;
|
||||
use crate::settings::types::PythonVersion;
|
||||
use crate::settings::{flags, Settings};
|
||||
use crate::settings::{defaults, flags, Settings};
|
||||
use crate::source_code::{Indexer, Locator, Stylist};
|
||||
|
||||
const VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||
@@ -87,14 +86,14 @@ pub fn defaultSettings() -> Result<JsValue, JsValue> {
|
||||
// Propagate defaults.
|
||||
allowed_confusables: Some(Vec::default()),
|
||||
builtins: Some(Vec::default()),
|
||||
dummy_variable_rgx: Some("^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$".to_string()),
|
||||
dummy_variable_rgx: Some(defaults::DUMMY_VARIABLE_RGX.as_str().to_string()),
|
||||
extend_ignore: Some(Vec::default()),
|
||||
extend_select: Some(Vec::default()),
|
||||
external: Some(Vec::default()),
|
||||
ignore: Some(Vec::default()),
|
||||
line_length: Some(88),
|
||||
select: Some(vec![RuleCodePrefix::E, RuleCodePrefix::F]),
|
||||
target_version: Some(PythonVersion::default()),
|
||||
line_length: Some(defaults::LINE_LENGTH),
|
||||
select: Some(defaults::PREFIXES.to_vec()),
|
||||
target_version: Some(defaults::TARGET_VERSION),
|
||||
// Ignore a bunch of options that don't make sense in a single-file editor.
|
||||
cache_dir: None,
|
||||
exclude: None,
|
||||
@@ -123,7 +122,7 @@ pub fn defaultSettings() -> Result<JsValue, JsValue> {
|
||||
flake8_errmsg: Some(flake8_errmsg::settings::Settings::default().into()),
|
||||
flake8_pytest_style: Some(flake8_pytest_style::settings::Settings::default().into()),
|
||||
flake8_quotes: Some(flake8_quotes::settings::Settings::default().into()),
|
||||
flake8_tidy_imports: Some(flake8_tidy_imports::settings::Settings::default().into()),
|
||||
flake8_tidy_imports: Some(flake8_tidy_imports::Settings::default().into()),
|
||||
flake8_import_conventions: Some(
|
||||
flake8_import_conventions::settings::Settings::default().into(),
|
||||
),
|
||||
|
||||
@@ -7,6 +7,7 @@ use rustpython_parser::lexer::LexResult;
|
||||
use crate::ast::types::Range;
|
||||
use crate::autofix::fix_file;
|
||||
use crate::checkers::ast::check_ast;
|
||||
use crate::checkers::filesystem::check_file_path;
|
||||
use crate::checkers::imports::check_imports;
|
||||
use crate::checkers::lines::check_lines;
|
||||
use crate::checkers::noqa::check_noqa;
|
||||
@@ -47,7 +48,7 @@ pub fn check_path(
|
||||
|
||||
// Collect doc lines. This requires a rare mix of tokens (for comments) and AST
|
||||
// (for docstrings), which demands special-casing at this level.
|
||||
let use_doc_lines = settings.enabled.contains(&RuleCode::W505);
|
||||
let use_doc_lines = settings.rules.enabled(&RuleCode::W505);
|
||||
let mut doc_lines = vec![];
|
||||
if use_doc_lines {
|
||||
doc_lines.extend(doc_lines_from_tokens(&tokens));
|
||||
@@ -55,22 +56,31 @@ pub fn check_path(
|
||||
|
||||
// Run the token-based rules.
|
||||
if settings
|
||||
.enabled
|
||||
.iter()
|
||||
.rules
|
||||
.iter_enabled()
|
||||
.any(|rule_code| matches!(rule_code.lint_source(), LintSource::Tokens))
|
||||
{
|
||||
diagnostics.extend(check_tokens(locator, &tokens, settings, autofix));
|
||||
}
|
||||
|
||||
// Run the filesystem-based rules.
|
||||
if settings
|
||||
.rules
|
||||
.iter_enabled()
|
||||
.any(|rule_code| matches!(rule_code.lint_source(), LintSource::Filesystem))
|
||||
{
|
||||
diagnostics.extend(check_file_path(path, settings));
|
||||
}
|
||||
|
||||
// Run the AST-based rules.
|
||||
let use_ast = settings
|
||||
.enabled
|
||||
.iter()
|
||||
.rules
|
||||
.iter_enabled()
|
||||
.any(|rule_code| matches!(rule_code.lint_source(), LintSource::Ast));
|
||||
let use_imports = !directives.isort.skip_file
|
||||
&& settings
|
||||
.enabled
|
||||
.iter()
|
||||
.rules
|
||||
.iter_enabled()
|
||||
.any(|rule_code| matches!(rule_code.lint_source(), LintSource::Imports));
|
||||
if use_ast || use_imports || use_doc_lines {
|
||||
match rustpython_helpers::parse_program_tokens(tokens, "<filename>") {
|
||||
@@ -106,7 +116,7 @@ pub fn check_path(
|
||||
}
|
||||
}
|
||||
Err(parse_error) => {
|
||||
if settings.enabled.contains(&RuleCode::E999) {
|
||||
if settings.rules.enabled(&RuleCode::E999) {
|
||||
diagnostics.push(Diagnostic::new(
|
||||
violations::SyntaxError(parse_error.error.to_string()),
|
||||
Range::new(parse_error.location, parse_error.location),
|
||||
@@ -124,8 +134,8 @@ pub fn check_path(
|
||||
|
||||
// Run the lines-based rules.
|
||||
if settings
|
||||
.enabled
|
||||
.iter()
|
||||
.rules
|
||||
.iter_enabled()
|
||||
.any(|rule_code| matches!(rule_code.lint_source(), LintSource::Lines))
|
||||
{
|
||||
diagnostics.extend(check_lines(
|
||||
@@ -140,8 +150,8 @@ pub fn check_path(
|
||||
// Enforce `noqa` directives.
|
||||
if (matches!(noqa, flags::Noqa::Enabled) && !diagnostics.is_empty())
|
||||
|| settings
|
||||
.enabled
|
||||
.iter()
|
||||
.rules
|
||||
.iter_enabled()
|
||||
.any(|rule_code| matches!(rule_code.lint_source(), LintSource::NoQa))
|
||||
{
|
||||
check_noqa(
|
||||
@@ -340,16 +350,16 @@ pub fn lint_fix(
|
||||
}
|
||||
|
||||
eprintln!(
|
||||
"
|
||||
r#"
|
||||
{}: Failed to converge after {} iterations.
|
||||
|
||||
This likely indicates a bug in `{}`. If you could open an issue at:
|
||||
|
||||
{}/issues
|
||||
{}/issues/new?title=%5BInfinite%20loop%5D
|
||||
|
||||
quoting the contents of `{}`, along with the `pyproject.toml` settings and executed command, we'd \
|
||||
be very appreciative!
|
||||
",
|
||||
quoting the contents of `{}`, along with the `pyproject.toml` settings and executed command, we'd be
|
||||
very appreciative!
|
||||
"#,
|
||||
"warning".yellow().bold(),
|
||||
MAX_ITERATIONS,
|
||||
CARGO_PKG_NAME,
|
||||
|
||||
15
src/noqa.rs
15
src/noqa.rs
@@ -9,6 +9,7 @@ use regex::Regex;
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
|
||||
use crate::registry::{Diagnostic, RuleCode, CODE_REDIRECTS};
|
||||
use crate::settings::hashable::HashableHashSet;
|
||||
use crate::source_code::LineEnding;
|
||||
|
||||
static NOQA_LINE_REGEX: Lazy<Regex> = Lazy::new(|| {
|
||||
@@ -84,7 +85,7 @@ pub fn add_noqa(
|
||||
diagnostics: &[Diagnostic],
|
||||
contents: &str,
|
||||
noqa_line_for: &IntMap<usize, usize>,
|
||||
external: &FxHashSet<String>,
|
||||
external: &HashableHashSet<String>,
|
||||
line_ending: &LineEnding,
|
||||
) -> Result<usize> {
|
||||
let (count, output) =
|
||||
@@ -97,7 +98,7 @@ fn add_noqa_inner(
|
||||
diagnostics: &[Diagnostic],
|
||||
contents: &str,
|
||||
noqa_line_for: &IntMap<usize, usize>,
|
||||
external: &FxHashSet<String>,
|
||||
external: &HashableHashSet<String>,
|
||||
line_ending: &LineEnding,
|
||||
) -> (usize, String) {
|
||||
let mut matches_by_line: FxHashMap<usize, FxHashSet<&RuleCode>> = FxHashMap::default();
|
||||
@@ -208,12 +209,12 @@ fn add_noqa_inner(
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use nohash_hasher::IntMap;
|
||||
use rustc_hash::FxHashSet;
|
||||
use rustpython_parser::ast::Location;
|
||||
|
||||
use crate::ast::types::Range;
|
||||
use crate::noqa::{add_noqa_inner, NOQA_LINE_REGEX};
|
||||
use crate::registry::Diagnostic;
|
||||
use crate::settings::hashable::HashableHashSet;
|
||||
use crate::source_code::LineEnding;
|
||||
use crate::violations;
|
||||
|
||||
@@ -236,7 +237,7 @@ mod tests {
|
||||
let diagnostics = vec![];
|
||||
let contents = "x = 1";
|
||||
let noqa_line_for = IntMap::default();
|
||||
let external = FxHashSet::default();
|
||||
let external = HashableHashSet::default();
|
||||
let (count, output) = add_noqa_inner(
|
||||
&diagnostics,
|
||||
contents,
|
||||
@@ -253,7 +254,7 @@ mod tests {
|
||||
)];
|
||||
let contents = "x = 1";
|
||||
let noqa_line_for = IntMap::default();
|
||||
let external = FxHashSet::default();
|
||||
let external = HashableHashSet::default();
|
||||
let (count, output) = add_noqa_inner(
|
||||
&diagnostics,
|
||||
contents,
|
||||
@@ -276,7 +277,7 @@ mod tests {
|
||||
];
|
||||
let contents = "x = 1 # noqa: E741\n";
|
||||
let noqa_line_for = IntMap::default();
|
||||
let external = FxHashSet::default();
|
||||
let external = HashableHashSet::default();
|
||||
let (count, output) = add_noqa_inner(
|
||||
&diagnostics,
|
||||
contents,
|
||||
@@ -299,7 +300,7 @@ mod tests {
|
||||
];
|
||||
let contents = "x = 1 # noqa";
|
||||
let noqa_line_for = IntMap::default();
|
||||
let external = FxHashSet::default();
|
||||
let external = HashableHashSet::default();
|
||||
let (count, output) = add_noqa_inner(
|
||||
&diagnostics,
|
||||
contents,
|
||||
|
||||
199
src/registry.rs
199
src/registry.rs
@@ -1,7 +1,5 @@
|
||||
//! Registry of [`RuleCode`] to [`DiagnosticKind`] mappings.
|
||||
|
||||
use std::fmt;
|
||||
|
||||
use itertools::Itertools;
|
||||
use once_cell::sync::Lazy;
|
||||
use ruff_macros::RuleCodePrefix;
|
||||
@@ -13,7 +11,7 @@ use strum_macros::{AsRefStr, Display, EnumIter, EnumString};
|
||||
use crate::ast::types::Range;
|
||||
use crate::fix::Fix;
|
||||
use crate::violation::Violation;
|
||||
use crate::violations;
|
||||
use crate::{rules, violations};
|
||||
|
||||
ruff_macros::define_rule_mapping!(
|
||||
// pycodestyle errors
|
||||
@@ -152,8 +150,8 @@ ruff_macros::define_rule_mapping!(
|
||||
// mccabe
|
||||
C901 => violations::FunctionIsTooComplex,
|
||||
// flake8-tidy-imports
|
||||
TID251 => violations::BannedApi,
|
||||
TID252 => violations::BannedRelativeImport,
|
||||
TID251 => rules::flake8_tidy_imports::banned_api::BannedApi,
|
||||
TID252 => rules::flake8_tidy_imports::relative_imports::RelativeImports,
|
||||
// flake8-return
|
||||
RET501 => violations::UnnecessaryReturnNone,
|
||||
RET502 => violations::ImplicitReturnValue,
|
||||
@@ -234,7 +232,7 @@ ruff_macros::define_rule_mapping!(
|
||||
UP008 => violations::SuperCallWithParameters,
|
||||
UP009 => violations::PEP3120UnnecessaryCodingComment,
|
||||
UP010 => violations::UnnecessaryFutureImport,
|
||||
UP011 => violations::UnnecessaryLRUCacheParams,
|
||||
UP011 => violations::LRUCacheWithoutParameters,
|
||||
UP012 => violations::UnnecessaryEncodeUTF8,
|
||||
UP013 => violations::ConvertTypedDictFunctionalToClass,
|
||||
UP014 => violations::ConvertNamedTupleFunctionalToClass,
|
||||
@@ -254,6 +252,8 @@ ruff_macros::define_rule_mapping!(
|
||||
UP028 => violations::RewriteYieldFrom,
|
||||
UP029 => violations::UnnecessaryBuiltinImport,
|
||||
UP030 => violations::FormatLiterals,
|
||||
UP032 => violations::FString,
|
||||
UP033 => violations::FunctoolsCache,
|
||||
// pydocstyle
|
||||
D100 => violations::PublicModule,
|
||||
D101 => violations::PublicClass,
|
||||
@@ -410,11 +410,14 @@ ruff_macros::define_rule_mapping!(
|
||||
// flake8-pie
|
||||
PIE790 => violations::NoUnnecessaryPass,
|
||||
PIE794 => violations::DupeClassFieldDefinitions,
|
||||
PIE796 => violations::PreferUniqueEnums,
|
||||
PIE807 => violations::PreferListBuiltin,
|
||||
// flake8-commas
|
||||
COM812 => violations::TrailingCommaMissing,
|
||||
COM818 => violations::TrailingCommaOnBareTupleProhibited,
|
||||
COM819 => violations::TrailingCommaProhibited,
|
||||
// flake8-no-pep420
|
||||
INP001 => violations::ImplicitNamespacePackage,
|
||||
// Ruff
|
||||
RUF001 => violations::AmbiguousUnicodeCharacterString,
|
||||
RUF002 => violations::AmbiguousUnicodeCharacterDocstring,
|
||||
@@ -458,23 +461,10 @@ pub enum RuleOrigin {
|
||||
Pylint,
|
||||
Flake8Pie,
|
||||
Flake8Commas,
|
||||
Flake8NoPep420,
|
||||
Ruff,
|
||||
}
|
||||
|
||||
pub enum Platform {
|
||||
PyPI,
|
||||
GitHub,
|
||||
}
|
||||
|
||||
impl fmt::Display for Platform {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Platform::PyPI => fmt.write_str("PyPI"),
|
||||
Platform::GitHub => fmt.write_str("GitHub"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub enum Prefixes {
|
||||
Single(RuleCodePrefix),
|
||||
Multiple(Vec<(RuleCodePrefix, &'static str)>),
|
||||
@@ -492,46 +482,9 @@ impl Prefixes {
|
||||
}
|
||||
}
|
||||
|
||||
impl RuleOrigin {
|
||||
pub fn title(&self) -> &'static str {
|
||||
match self {
|
||||
RuleOrigin::Eradicate => "eradicate",
|
||||
RuleOrigin::Flake82020 => "flake8-2020",
|
||||
RuleOrigin::Flake8Annotations => "flake8-annotations",
|
||||
RuleOrigin::Flake8Bandit => "flake8-bandit",
|
||||
RuleOrigin::Flake8BlindExcept => "flake8-blind-except",
|
||||
RuleOrigin::Flake8BooleanTrap => "flake8-boolean-trap",
|
||||
RuleOrigin::Flake8Bugbear => "flake8-bugbear",
|
||||
RuleOrigin::Flake8Builtins => "flake8-builtins",
|
||||
RuleOrigin::Flake8Comprehensions => "flake8-comprehensions",
|
||||
RuleOrigin::Flake8Debugger => "flake8-debugger",
|
||||
RuleOrigin::Flake8ErrMsg => "flake8-errmsg",
|
||||
RuleOrigin::Flake8ImplicitStrConcat => "flake8-implicit-str-concat",
|
||||
RuleOrigin::Flake8ImportConventions => "flake8-import-conventions",
|
||||
RuleOrigin::Flake8Print => "flake8-print",
|
||||
RuleOrigin::Flake8PytestStyle => "flake8-pytest-style",
|
||||
RuleOrigin::Flake8Quotes => "flake8-quotes",
|
||||
RuleOrigin::Flake8Return => "flake8-return",
|
||||
RuleOrigin::Flake8TidyImports => "flake8-tidy-imports",
|
||||
RuleOrigin::Flake8Simplify => "flake8-simplify",
|
||||
RuleOrigin::Flake8UnusedArguments => "flake8-unused-arguments",
|
||||
RuleOrigin::Flake8Datetimez => "flake8-datetimez",
|
||||
RuleOrigin::Isort => "isort",
|
||||
RuleOrigin::McCabe => "mccabe",
|
||||
RuleOrigin::PandasVet => "pandas-vet",
|
||||
RuleOrigin::PEP8Naming => "pep8-naming",
|
||||
RuleOrigin::Pycodestyle => "pycodestyle",
|
||||
RuleOrigin::Pydocstyle => "pydocstyle",
|
||||
RuleOrigin::Pyflakes => "Pyflakes",
|
||||
RuleOrigin::PygrepHooks => "pygrep-hooks",
|
||||
RuleOrigin::Pylint => "Pylint",
|
||||
RuleOrigin::Pyupgrade => "pyupgrade",
|
||||
RuleOrigin::Flake8Pie => "flake8-pie",
|
||||
RuleOrigin::Flake8Commas => "flake8-commas",
|
||||
RuleOrigin::Ruff => "Ruff-specific rules",
|
||||
}
|
||||
}
|
||||
include!(concat!(env!("OUT_DIR"), "/origin.rs"));
|
||||
|
||||
impl RuleOrigin {
|
||||
pub fn prefixes(&self) -> Prefixes {
|
||||
match self {
|
||||
RuleOrigin::Eradicate => Prefixes::Single(RuleCodePrefix::ERA),
|
||||
@@ -575,134 +528,10 @@ impl RuleOrigin {
|
||||
RuleOrigin::Pyupgrade => Prefixes::Single(RuleCodePrefix::UP),
|
||||
RuleOrigin::Flake8Pie => Prefixes::Single(RuleCodePrefix::PIE),
|
||||
RuleOrigin::Flake8Commas => Prefixes::Single(RuleCodePrefix::COM),
|
||||
RuleOrigin::Flake8NoPep420 => Prefixes::Single(RuleCodePrefix::INP),
|
||||
RuleOrigin::Ruff => Prefixes::Single(RuleCodePrefix::RUF),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn url(&self) -> Option<(&'static str, &'static Platform)> {
|
||||
match self {
|
||||
RuleOrigin::Eradicate => {
|
||||
Some(("https://pypi.org/project/eradicate/2.1.0/", &Platform::PyPI))
|
||||
}
|
||||
RuleOrigin::Flake82020 => Some((
|
||||
"https://pypi.org/project/flake8-2020/1.7.0/",
|
||||
&Platform::PyPI,
|
||||
)),
|
||||
RuleOrigin::Flake8Annotations => Some((
|
||||
"https://pypi.org/project/flake8-annotations/2.9.1/",
|
||||
&Platform::PyPI,
|
||||
)),
|
||||
RuleOrigin::Flake8Bandit => Some((
|
||||
"https://pypi.org/project/flake8-bandit/4.1.1/",
|
||||
&Platform::PyPI,
|
||||
)),
|
||||
RuleOrigin::Flake8BlindExcept => Some((
|
||||
"https://pypi.org/project/flake8-blind-except/0.2.1/",
|
||||
&Platform::PyPI,
|
||||
)),
|
||||
RuleOrigin::Flake8BooleanTrap => Some((
|
||||
"https://pypi.org/project/flake8-boolean-trap/0.1.0/",
|
||||
&Platform::PyPI,
|
||||
)),
|
||||
RuleOrigin::Flake8Bugbear => Some((
|
||||
"https://pypi.org/project/flake8-bugbear/22.10.27/",
|
||||
&Platform::PyPI,
|
||||
)),
|
||||
RuleOrigin::Flake8Builtins => Some((
|
||||
"https://pypi.org/project/flake8-builtins/2.0.1/",
|
||||
&Platform::PyPI,
|
||||
)),
|
||||
RuleOrigin::Flake8Comprehensions => Some((
|
||||
"https://pypi.org/project/flake8-comprehensions/3.10.1/",
|
||||
&Platform::PyPI,
|
||||
)),
|
||||
RuleOrigin::Flake8Debugger => Some((
|
||||
"https://pypi.org/project/flake8-debugger/4.1.2/",
|
||||
&Platform::PyPI,
|
||||
)),
|
||||
RuleOrigin::Flake8ErrMsg => Some((
|
||||
"https://pypi.org/project/flake8-errmsg/0.4.0/",
|
||||
&Platform::PyPI,
|
||||
)),
|
||||
RuleOrigin::Flake8ImplicitStrConcat => Some((
|
||||
"https://pypi.org/project/flake8-implicit-str-concat/0.3.0/",
|
||||
&Platform::PyPI,
|
||||
)),
|
||||
RuleOrigin::Flake8ImportConventions => None,
|
||||
RuleOrigin::Flake8Print => Some((
|
||||
"https://pypi.org/project/flake8-print/5.0.0/",
|
||||
&Platform::PyPI,
|
||||
)),
|
||||
RuleOrigin::Flake8PytestStyle => Some((
|
||||
"https://pypi.org/project/flake8-pytest-style/1.6.0/",
|
||||
&Platform::PyPI,
|
||||
)),
|
||||
RuleOrigin::Flake8Quotes => Some((
|
||||
"https://pypi.org/project/flake8-quotes/3.3.1/",
|
||||
&Platform::PyPI,
|
||||
)),
|
||||
RuleOrigin::Flake8Return => Some((
|
||||
"https://pypi.org/project/flake8-return/1.2.0/",
|
||||
&Platform::PyPI,
|
||||
)),
|
||||
RuleOrigin::Flake8Simplify => Some((
|
||||
"https://pypi.org/project/flake8-simplify/0.19.3/",
|
||||
&Platform::PyPI,
|
||||
)),
|
||||
RuleOrigin::Flake8TidyImports => Some((
|
||||
"https://pypi.org/project/flake8-tidy-imports/4.8.0/",
|
||||
&Platform::PyPI,
|
||||
)),
|
||||
RuleOrigin::Flake8UnusedArguments => Some((
|
||||
"https://pypi.org/project/flake8-unused-arguments/0.0.12/",
|
||||
&Platform::PyPI,
|
||||
)),
|
||||
RuleOrigin::Flake8Datetimez => Some((
|
||||
"https://pypi.org/project/flake8-datetimez/20.10.0/",
|
||||
&Platform::PyPI,
|
||||
)),
|
||||
RuleOrigin::Isort => Some(("https://pypi.org/project/isort/5.10.1/", &Platform::PyPI)),
|
||||
RuleOrigin::McCabe => Some(("https://pypi.org/project/mccabe/0.7.0/", &Platform::PyPI)),
|
||||
RuleOrigin::PandasVet => Some((
|
||||
"https://pypi.org/project/pandas-vet/0.2.3/",
|
||||
&Platform::PyPI,
|
||||
)),
|
||||
RuleOrigin::PEP8Naming => Some((
|
||||
"https://pypi.org/project/pep8-naming/0.13.2/",
|
||||
&Platform::PyPI,
|
||||
)),
|
||||
RuleOrigin::Pycodestyle => Some((
|
||||
"https://pypi.org/project/pycodestyle/2.9.1/",
|
||||
&Platform::PyPI,
|
||||
)),
|
||||
RuleOrigin::Pydocstyle => Some((
|
||||
"https://pypi.org/project/pydocstyle/6.1.1/",
|
||||
&Platform::PyPI,
|
||||
)),
|
||||
RuleOrigin::Pyflakes => {
|
||||
Some(("https://pypi.org/project/pyflakes/2.5.0/", &Platform::PyPI))
|
||||
}
|
||||
RuleOrigin::Pylint => {
|
||||
Some(("https://pypi.org/project/pylint/2.15.7/", &Platform::PyPI))
|
||||
}
|
||||
RuleOrigin::PygrepHooks => Some((
|
||||
"https://github.com/pre-commit/pygrep-hooks",
|
||||
&Platform::GitHub,
|
||||
)),
|
||||
RuleOrigin::Pyupgrade => {
|
||||
Some(("https://pypi.org/project/pyupgrade/3.2.0/", &Platform::PyPI))
|
||||
}
|
||||
RuleOrigin::Flake8Pie => Some((
|
||||
"https://pypi.org/project/flake8-pie/0.16.0/",
|
||||
&Platform::PyPI,
|
||||
)),
|
||||
RuleOrigin::Flake8Commas => Some((
|
||||
"https://pypi.org/project/flake8-commas/2.1.0/",
|
||||
&Platform::PyPI,
|
||||
)),
|
||||
RuleOrigin::Ruff => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub enum LintSource {
|
||||
@@ -712,6 +541,7 @@ pub enum LintSource {
|
||||
Tokens,
|
||||
Imports,
|
||||
NoQa,
|
||||
Filesystem,
|
||||
}
|
||||
|
||||
impl RuleCode {
|
||||
@@ -742,6 +572,7 @@ impl RuleCode {
|
||||
| RuleCode::RUF003 => &LintSource::Tokens,
|
||||
RuleCode::E902 => &LintSource::Io,
|
||||
RuleCode::I001 | RuleCode::I002 => &LintSource::Imports,
|
||||
RuleCode::INP001 => &LintSource::Filesystem,
|
||||
_ => &LintSource::Ast,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
//! Rules from [eradicate](https://pypi.org/project/eradicate/2.1.0/).
|
||||
pub(crate) mod detection;
|
||||
pub(crate) mod rules;
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ pub fn commented_out_code(
|
||||
if is_standalone_comment(&line) && comment_contains_code(&line, &settings.task_tags[..]) {
|
||||
let mut diagnostic = Diagnostic::new(violations::CommentedOutCode, Range::new(start, end));
|
||||
if matches!(autofix, flags::Autofix::Enabled)
|
||||
&& settings.fixable.contains(&RuleCode::ERA001)
|
||||
&& settings.rules.should_fix(&RuleCode::ERA001)
|
||||
{
|
||||
diagnostic.amend(Fix::deletion(location, end_location));
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
//! Rules from [flake8-2020](https://pypi.org/project/flake8-2020/1.7.0/).
|
||||
pub(crate) mod rules;
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -27,14 +27,13 @@ pub fn subscript(checker: &mut Checker, value: &Expr, slice: &Expr) {
|
||||
..
|
||||
} = &upper.node
|
||||
{
|
||||
if *i == BigInt::from(1) && checker.settings.enabled.contains(&RuleCode::YTT303)
|
||||
{
|
||||
if *i == BigInt::from(1) && checker.settings.rules.enabled(&RuleCode::YTT303) {
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
violations::SysVersionSlice1Referenced,
|
||||
Range::from_located(value),
|
||||
));
|
||||
} else if *i == BigInt::from(3)
|
||||
&& checker.settings.enabled.contains(&RuleCode::YTT101)
|
||||
&& checker.settings.rules.enabled(&RuleCode::YTT101)
|
||||
{
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
violations::SysVersionSlice3Referenced,
|
||||
@@ -48,13 +47,12 @@ pub fn subscript(checker: &mut Checker, value: &Expr, slice: &Expr) {
|
||||
value: Constant::Int(i),
|
||||
..
|
||||
} => {
|
||||
if *i == BigInt::from(2) && checker.settings.enabled.contains(&RuleCode::YTT102) {
|
||||
if *i == BigInt::from(2) && checker.settings.rules.enabled(&RuleCode::YTT102) {
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
violations::SysVersion2Referenced,
|
||||
Range::from_located(value),
|
||||
));
|
||||
} else if *i == BigInt::from(0)
|
||||
&& checker.settings.enabled.contains(&RuleCode::YTT301)
|
||||
} else if *i == BigInt::from(0) && checker.settings.rules.enabled(&RuleCode::YTT301)
|
||||
{
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
violations::SysVersion0Referenced,
|
||||
@@ -91,7 +89,7 @@ pub fn compare(checker: &mut Checker, left: &Expr, ops: &[Cmpop], comparators: &
|
||||
) = (ops, comparators)
|
||||
{
|
||||
if *n == BigInt::from(3)
|
||||
&& checker.settings.enabled.contains(&RuleCode::YTT201)
|
||||
&& checker.settings.rules.enabled(&RuleCode::YTT201)
|
||||
{
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
violations::SysVersionInfo0Eq3Referenced,
|
||||
@@ -112,7 +110,7 @@ pub fn compare(checker: &mut Checker, left: &Expr, ops: &[Cmpop], comparators: &
|
||||
}],
|
||||
) = (ops, comparators)
|
||||
{
|
||||
if checker.settings.enabled.contains(&RuleCode::YTT203) {
|
||||
if checker.settings.rules.enabled(&RuleCode::YTT203) {
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
violations::SysVersionInfo1CmpInt,
|
||||
Range::from_located(left),
|
||||
@@ -138,7 +136,7 @@ pub fn compare(checker: &mut Checker, left: &Expr, ops: &[Cmpop], comparators: &
|
||||
}],
|
||||
) = (ops, comparators)
|
||||
{
|
||||
if checker.settings.enabled.contains(&RuleCode::YTT204) {
|
||||
if checker.settings.rules.enabled(&RuleCode::YTT204) {
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
violations::SysVersionInfoMinorCmpInt,
|
||||
Range::from_located(left),
|
||||
@@ -164,13 +162,13 @@ pub fn compare(checker: &mut Checker, left: &Expr, ops: &[Cmpop], comparators: &
|
||||
) = (ops, comparators)
|
||||
{
|
||||
if s.len() == 1 {
|
||||
if checker.settings.enabled.contains(&RuleCode::YTT302) {
|
||||
if checker.settings.rules.enabled(&RuleCode::YTT302) {
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
violations::SysVersionCmpStr10,
|
||||
Range::from_located(left),
|
||||
));
|
||||
}
|
||||
} else if checker.settings.enabled.contains(&RuleCode::YTT103) {
|
||||
} else if checker.settings.rules.enabled(&RuleCode::YTT103) {
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
violations::SysVersionCmpStr3,
|
||||
Range::from_located(left),
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
//! Rules from [flake8-annotations](https://pypi.org/project/flake8-annotations/2.9.1/).
|
||||
mod fixes;
|
||||
pub(crate) mod helpers;
|
||||
pub(crate) mod rules;
|
||||
|
||||
@@ -85,14 +85,14 @@ pub fn definition(checker: &mut Checker, definition: &Definition, visibility: &V
|
||||
.chain(args.kwonlyargs.iter())
|
||||
{
|
||||
if let Some(expr) = &arg.node.annotation {
|
||||
if checker.settings.enabled.contains(&RuleCode::ANN401) {
|
||||
if checker.settings.rules.enabled(&RuleCode::ANN401) {
|
||||
check_dynamically_typed(checker, expr, || arg.node.arg.to_string());
|
||||
};
|
||||
} else {
|
||||
if !(checker.settings.flake8_annotations.suppress_dummy_args
|
||||
&& checker.settings.dummy_variable_rgx.is_match(&arg.node.arg))
|
||||
{
|
||||
if checker.settings.enabled.contains(&RuleCode::ANN001) {
|
||||
if checker.settings.rules.enabled(&RuleCode::ANN001) {
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
violations::MissingTypeFunctionArgument(arg.node.arg.to_string()),
|
||||
Range::from_located(arg),
|
||||
@@ -106,7 +106,7 @@ pub fn definition(checker: &mut Checker, definition: &Definition, visibility: &V
|
||||
if let Some(arg) = &args.vararg {
|
||||
if let Some(expr) = &arg.node.annotation {
|
||||
if !checker.settings.flake8_annotations.allow_star_arg_any {
|
||||
if checker.settings.enabled.contains(&RuleCode::ANN401) {
|
||||
if checker.settings.rules.enabled(&RuleCode::ANN401) {
|
||||
let name = arg.node.arg.to_string();
|
||||
check_dynamically_typed(checker, expr, || format!("*{name}"));
|
||||
}
|
||||
@@ -115,7 +115,7 @@ pub fn definition(checker: &mut Checker, definition: &Definition, visibility: &V
|
||||
if !(checker.settings.flake8_annotations.suppress_dummy_args
|
||||
&& checker.settings.dummy_variable_rgx.is_match(&arg.node.arg))
|
||||
{
|
||||
if checker.settings.enabled.contains(&RuleCode::ANN002) {
|
||||
if checker.settings.rules.enabled(&RuleCode::ANN002) {
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
violations::MissingTypeArgs(arg.node.arg.to_string()),
|
||||
Range::from_located(arg),
|
||||
@@ -129,7 +129,7 @@ pub fn definition(checker: &mut Checker, definition: &Definition, visibility: &V
|
||||
if let Some(arg) = &args.kwarg {
|
||||
if let Some(expr) = &arg.node.annotation {
|
||||
if !checker.settings.flake8_annotations.allow_star_arg_any {
|
||||
if checker.settings.enabled.contains(&RuleCode::ANN401) {
|
||||
if checker.settings.rules.enabled(&RuleCode::ANN401) {
|
||||
let name = arg.node.arg.to_string();
|
||||
check_dynamically_typed(checker, expr, || format!("**{name}"));
|
||||
}
|
||||
@@ -138,7 +138,7 @@ pub fn definition(checker: &mut Checker, definition: &Definition, visibility: &V
|
||||
if !(checker.settings.flake8_annotations.suppress_dummy_args
|
||||
&& checker.settings.dummy_variable_rgx.is_match(&arg.node.arg))
|
||||
{
|
||||
if checker.settings.enabled.contains(&RuleCode::ANN003) {
|
||||
if checker.settings.rules.enabled(&RuleCode::ANN003) {
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
violations::MissingTypeKwargs(arg.node.arg.to_string()),
|
||||
Range::from_located(arg),
|
||||
@@ -150,7 +150,7 @@ pub fn definition(checker: &mut Checker, definition: &Definition, visibility: &V
|
||||
|
||||
// ANN201, ANN202, ANN401
|
||||
if let Some(expr) = &returns {
|
||||
if checker.settings.enabled.contains(&RuleCode::ANN401) {
|
||||
if checker.settings.rules.enabled(&RuleCode::ANN401) {
|
||||
check_dynamically_typed(checker, expr, || name.to_string());
|
||||
};
|
||||
} else {
|
||||
@@ -164,7 +164,7 @@ pub fn definition(checker: &mut Checker, definition: &Definition, visibility: &V
|
||||
|
||||
match visibility {
|
||||
Visibility::Public => {
|
||||
if checker.settings.enabled.contains(&RuleCode::ANN201) {
|
||||
if checker.settings.rules.enabled(&RuleCode::ANN201) {
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
violations::MissingReturnTypePublicFunction(name.to_string()),
|
||||
helpers::identifier_range(stmt, checker.locator),
|
||||
@@ -172,7 +172,7 @@ pub fn definition(checker: &mut Checker, definition: &Definition, visibility: &V
|
||||
}
|
||||
}
|
||||
Visibility::Private => {
|
||||
if checker.settings.enabled.contains(&RuleCode::ANN202) {
|
||||
if checker.settings.rules.enabled(&RuleCode::ANN202) {
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
violations::MissingReturnTypePrivateFunction(name.to_string()),
|
||||
helpers::identifier_range(stmt, checker.locator),
|
||||
@@ -203,14 +203,14 @@ pub fn definition(checker: &mut Checker, definition: &Definition, visibility: &V
|
||||
// ANN401 for dynamically typed arguments
|
||||
if let Some(annotation) = &arg.node.annotation {
|
||||
has_any_typed_arg = true;
|
||||
if checker.settings.enabled.contains(&RuleCode::ANN401) {
|
||||
if checker.settings.rules.enabled(&RuleCode::ANN401) {
|
||||
check_dynamically_typed(checker, annotation, || arg.node.arg.to_string());
|
||||
}
|
||||
} else {
|
||||
if !(checker.settings.flake8_annotations.suppress_dummy_args
|
||||
&& checker.settings.dummy_variable_rgx.is_match(&arg.node.arg))
|
||||
{
|
||||
if checker.settings.enabled.contains(&RuleCode::ANN001) {
|
||||
if checker.settings.rules.enabled(&RuleCode::ANN001) {
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
violations::MissingTypeFunctionArgument(arg.node.arg.to_string()),
|
||||
Range::from_located(arg),
|
||||
@@ -225,7 +225,7 @@ pub fn definition(checker: &mut Checker, definition: &Definition, visibility: &V
|
||||
has_any_typed_arg = true;
|
||||
if let Some(expr) = &arg.node.annotation {
|
||||
if !checker.settings.flake8_annotations.allow_star_arg_any {
|
||||
if checker.settings.enabled.contains(&RuleCode::ANN401) {
|
||||
if checker.settings.rules.enabled(&RuleCode::ANN401) {
|
||||
let name = arg.node.arg.to_string();
|
||||
check_dynamically_typed(checker, expr, || format!("*{name}"));
|
||||
}
|
||||
@@ -234,7 +234,7 @@ pub fn definition(checker: &mut Checker, definition: &Definition, visibility: &V
|
||||
if !(checker.settings.flake8_annotations.suppress_dummy_args
|
||||
&& checker.settings.dummy_variable_rgx.is_match(&arg.node.arg))
|
||||
{
|
||||
if checker.settings.enabled.contains(&RuleCode::ANN002) {
|
||||
if checker.settings.rules.enabled(&RuleCode::ANN002) {
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
violations::MissingTypeArgs(arg.node.arg.to_string()),
|
||||
Range::from_located(arg),
|
||||
@@ -249,7 +249,7 @@ pub fn definition(checker: &mut Checker, definition: &Definition, visibility: &V
|
||||
has_any_typed_arg = true;
|
||||
if let Some(expr) = &arg.node.annotation {
|
||||
if !checker.settings.flake8_annotations.allow_star_arg_any {
|
||||
if checker.settings.enabled.contains(&RuleCode::ANN401) {
|
||||
if checker.settings.rules.enabled(&RuleCode::ANN401) {
|
||||
let name = arg.node.arg.to_string();
|
||||
check_dynamically_typed(checker, expr, || format!("**{name}"));
|
||||
}
|
||||
@@ -258,7 +258,7 @@ pub fn definition(checker: &mut Checker, definition: &Definition, visibility: &V
|
||||
if !(checker.settings.flake8_annotations.suppress_dummy_args
|
||||
&& checker.settings.dummy_variable_rgx.is_match(&arg.node.arg))
|
||||
{
|
||||
if checker.settings.enabled.contains(&RuleCode::ANN003) {
|
||||
if checker.settings.rules.enabled(&RuleCode::ANN003) {
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
violations::MissingTypeKwargs(arg.node.arg.to_string()),
|
||||
Range::from_located(arg),
|
||||
@@ -273,14 +273,14 @@ pub fn definition(checker: &mut Checker, definition: &Definition, visibility: &V
|
||||
if let Some(arg) = args.args.first() {
|
||||
if arg.node.annotation.is_none() {
|
||||
if visibility::is_classmethod(checker, cast::decorator_list(stmt)) {
|
||||
if checker.settings.enabled.contains(&RuleCode::ANN102) {
|
||||
if checker.settings.rules.enabled(&RuleCode::ANN102) {
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
violations::MissingTypeCls(arg.node.arg.to_string()),
|
||||
Range::from_located(arg),
|
||||
));
|
||||
}
|
||||
} else {
|
||||
if checker.settings.enabled.contains(&RuleCode::ANN101) {
|
||||
if checker.settings.rules.enabled(&RuleCode::ANN101) {
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
violations::MissingTypeSelf(arg.node.arg.to_string()),
|
||||
Range::from_located(arg),
|
||||
@@ -293,7 +293,7 @@ pub fn definition(checker: &mut Checker, definition: &Definition, visibility: &V
|
||||
|
||||
// ANN201, ANN202
|
||||
if let Some(expr) = &returns {
|
||||
if checker.settings.enabled.contains(&RuleCode::ANN401) {
|
||||
if checker.settings.rules.enabled(&RuleCode::ANN401) {
|
||||
check_dynamically_typed(checker, expr, || name.to_string());
|
||||
}
|
||||
} else {
|
||||
@@ -306,14 +306,14 @@ pub fn definition(checker: &mut Checker, definition: &Definition, visibility: &V
|
||||
}
|
||||
|
||||
if visibility::is_classmethod(checker, cast::decorator_list(stmt)) {
|
||||
if checker.settings.enabled.contains(&RuleCode::ANN206) {
|
||||
if checker.settings.rules.enabled(&RuleCode::ANN206) {
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
violations::MissingReturnTypeClassMethod(name.to_string()),
|
||||
helpers::identifier_range(stmt, checker.locator),
|
||||
));
|
||||
}
|
||||
} else if visibility::is_staticmethod(checker, cast::decorator_list(stmt)) {
|
||||
if checker.settings.enabled.contains(&RuleCode::ANN205) {
|
||||
if checker.settings.rules.enabled(&RuleCode::ANN205) {
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
violations::MissingReturnTypeStaticMethod(name.to_string()),
|
||||
helpers::identifier_range(stmt, checker.locator),
|
||||
@@ -322,7 +322,7 @@ pub fn definition(checker: &mut Checker, definition: &Definition, visibility: &V
|
||||
} else if visibility::is_init(cast::name(stmt)) {
|
||||
// Allow omission of return annotation in `__init__` functions, as long as at
|
||||
// least one argument is typed.
|
||||
if checker.settings.enabled.contains(&RuleCode::ANN204) {
|
||||
if checker.settings.rules.enabled(&RuleCode::ANN204) {
|
||||
if !(checker.settings.flake8_annotations.mypy_init_return
|
||||
&& has_any_typed_arg)
|
||||
{
|
||||
@@ -342,7 +342,7 @@ pub fn definition(checker: &mut Checker, definition: &Definition, visibility: &V
|
||||
}
|
||||
}
|
||||
} else if visibility::is_magic(cast::name(stmt)) {
|
||||
if checker.settings.enabled.contains(&RuleCode::ANN204) {
|
||||
if checker.settings.rules.enabled(&RuleCode::ANN204) {
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
violations::MissingReturnTypeSpecialMethod(name.to_string()),
|
||||
helpers::identifier_range(stmt, checker.locator),
|
||||
@@ -351,7 +351,7 @@ pub fn definition(checker: &mut Checker, definition: &Definition, visibility: &V
|
||||
} else {
|
||||
match visibility {
|
||||
Visibility::Public => {
|
||||
if checker.settings.enabled.contains(&RuleCode::ANN201) {
|
||||
if checker.settings.rules.enabled(&RuleCode::ANN201) {
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
violations::MissingReturnTypePublicFunction(name.to_string()),
|
||||
helpers::identifier_range(stmt, checker.locator),
|
||||
@@ -359,7 +359,7 @@ pub fn definition(checker: &mut Checker, definition: &Definition, visibility: &V
|
||||
}
|
||||
}
|
||||
Visibility::Private => {
|
||||
if checker.settings.enabled.contains(&RuleCode::ANN202) {
|
||||
if checker.settings.rules.enabled(&RuleCode::ANN202) {
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
violations::MissingReturnTypePrivateFunction(name.to_string()),
|
||||
helpers::identifier_range(stmt, checker.locator),
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
//! Rules from [flake8-bandit](https://pypi.org/project/flake8-bandit/4.1.1/).
|
||||
mod helpers;
|
||||
pub(crate) mod rules;
|
||||
pub mod settings;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
//! Rules from [flake8-blind-except](https://pypi.org/project/flake8-blind-except/0.2.1/).
|
||||
pub(crate) mod rules;
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
//! Rules from [flake8-boolean-trap](https://pypi.org/project/flake8-boolean-trap/0.1.0/).
|
||||
pub(crate) mod rules;
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
//! Rules from [flake8-bugbear](https://pypi.org/project/flake8-bugbear/22.10.27/).
|
||||
pub(crate) mod rules;
|
||||
pub mod settings;
|
||||
|
||||
|
||||
@@ -76,7 +76,7 @@ pub fn abstract_base_class(
|
||||
let has_abstract_decorator = is_abstract(checker, decorator_list);
|
||||
has_abstract_method |= has_abstract_decorator;
|
||||
|
||||
if !checker.settings.enabled.contains(&RuleCode::B027) {
|
||||
if !checker.settings.rules.enabled(&RuleCode::B027) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -87,7 +87,7 @@ pub fn abstract_base_class(
|
||||
));
|
||||
}
|
||||
}
|
||||
if checker.settings.enabled.contains(&RuleCode::B024) {
|
||||
if checker.settings.rules.enabled(&RuleCode::B024) {
|
||||
if !has_abstract_method {
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
violations::AbstractBaseClassWithoutAbstractMethod(name.to_string()),
|
||||
|
||||
@@ -41,7 +41,7 @@ fn duplicate_handler_exceptions<'a>(
|
||||
}
|
||||
}
|
||||
|
||||
if checker.settings.enabled.contains(&RuleCode::B014) {
|
||||
if checker.settings.rules.enabled(&RuleCode::B014) {
|
||||
// TODO(charlie): Handle "BaseException" and redundant exception aliases.
|
||||
if !duplicates.is_empty() {
|
||||
let mut diagnostic = Diagnostic::new(
|
||||
@@ -105,7 +105,7 @@ pub fn duplicate_exceptions(checker: &mut Checker, handlers: &[Excepthandler]) {
|
||||
}
|
||||
}
|
||||
|
||||
if checker.settings.enabled.contains(&RuleCode::B025) {
|
||||
if checker.settings.rules.enabled(&RuleCode::B025) {
|
||||
for (name, exprs) in duplicates {
|
||||
for expr in exprs {
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
//! Rules from [flake8-builtins](https://pypi.org/project/flake8-builtins/2.0.1/).
|
||||
pub(crate) mod rules;
|
||||
pub(crate) mod types;
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
//! Rules from [flake8-commas](https://pypi.org/project/flake8-commas/2.1.0/).
|
||||
pub(crate) mod rules;
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -4,8 +4,8 @@ use rustpython_parser::token::Tok;
|
||||
|
||||
use crate::ast::types::Range;
|
||||
use crate::fix::Fix;
|
||||
use crate::registry::Diagnostic;
|
||||
use crate::source_code::Locator;
|
||||
use crate::registry::{Diagnostic, RuleCode};
|
||||
use crate::settings::{flags, Settings};
|
||||
use crate::violations;
|
||||
|
||||
/// Simplified token type.
|
||||
@@ -108,8 +108,11 @@ impl Context {
|
||||
}
|
||||
|
||||
/// COM812, COM818, COM819
|
||||
#[allow(clippy::if_same_then_else, clippy::needless_bool)]
|
||||
pub fn trailing_commas(tokens: &[LexResult], _locator: &Locator) -> Vec<Diagnostic> {
|
||||
pub fn trailing_commas(
|
||||
tokens: &[LexResult],
|
||||
settings: &Settings,
|
||||
autofix: flags::Autofix,
|
||||
) -> Vec<Diagnostic> {
|
||||
let mut diagnostics = vec![];
|
||||
|
||||
let tokens = tokens
|
||||
@@ -202,12 +205,8 @@ pub fn trailing_commas(tokens: &[LexResult], _locator: &Locator) -> Vec<Diagnost
|
||||
if comma_allowed && !is_singleton_tuplish {
|
||||
true
|
||||
// Lambdas not handled by comma_allowed so handle it specially.
|
||||
} else if context.type_ == ContextType::LambdaParameters
|
||||
&& token.type_ == TokenType::Colon
|
||||
{
|
||||
true
|
||||
} else {
|
||||
false
|
||||
context.type_ == ContextType::LambdaParameters && token.type_ == TokenType::Colon
|
||||
}
|
||||
};
|
||||
if comma_prohibited {
|
||||
@@ -219,7 +218,11 @@ pub fn trailing_commas(tokens: &[LexResult], _locator: &Locator) -> Vec<Diagnost
|
||||
end_location: comma.2,
|
||||
},
|
||||
);
|
||||
diagnostic.amend(Fix::deletion(comma.0, comma.2));
|
||||
if matches!(autofix, flags::Autofix::Enabled)
|
||||
&& settings.rules.should_fix(&RuleCode::COM819)
|
||||
{
|
||||
diagnostic.amend(Fix::deletion(comma.0, comma.2));
|
||||
}
|
||||
diagnostics.push(diagnostic);
|
||||
}
|
||||
|
||||
@@ -229,14 +232,13 @@ pub fn trailing_commas(tokens: &[LexResult], _locator: &Locator) -> Vec<Diagnost
|
||||
prev.type_ == TokenType::Comma && token.type_ == TokenType::Newline;
|
||||
if bare_comma_prohibited {
|
||||
let comma = prev.spanned.unwrap();
|
||||
let diagnostic = Diagnostic::new(
|
||||
diagnostics.push(Diagnostic::new(
|
||||
violations::TrailingCommaOnBareTupleProhibited,
|
||||
Range {
|
||||
location: comma.0,
|
||||
end_location: comma.2,
|
||||
},
|
||||
);
|
||||
diagnostics.push(diagnostic);
|
||||
));
|
||||
}
|
||||
|
||||
// Comma is required if:
|
||||
@@ -262,7 +264,11 @@ pub fn trailing_commas(tokens: &[LexResult], _locator: &Locator) -> Vec<Diagnost
|
||||
end_location: missing_comma.2,
|
||||
},
|
||||
);
|
||||
diagnostic.amend(Fix::insertion(",".to_owned(), missing_comma.2));
|
||||
if matches!(autofix, flags::Autofix::Enabled)
|
||||
&& settings.rules.should_fix(&RuleCode::COM812)
|
||||
{
|
||||
diagnostic.amend(Fix::insertion(",".to_owned(), missing_comma.2));
|
||||
}
|
||||
diagnostics.push(diagnostic);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
//! Rules from [flake8-comprehensions](https://pypi.org/project/flake8-comprehensions/3.10.1/).
|
||||
mod fixes;
|
||||
pub(crate) mod rules;
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
//! Rules from [flake8-datetimez](https://pypi.org/project/flake8-datetimez/20.10.0/).
|
||||
pub(crate) mod rules;
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
//! Rules from [flake8-debugger](https://pypi.org/project/flake8-debugger/4.1.2/).
|
||||
pub(crate) mod rules;
|
||||
pub(crate) mod types;
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
//! Rules from [flake8-errmsg](https://pypi.org/project/flake8-errmsg/0.4.0/).
|
||||
pub(crate) mod rules;
|
||||
pub mod settings;
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ pub fn string_in_exception(checker: &mut Checker, exc: &Expr) {
|
||||
value: Constant::Str(string),
|
||||
..
|
||||
} => {
|
||||
if checker.settings.enabled.contains(&RuleCode::EM101) {
|
||||
if checker.settings.rules.enabled(&RuleCode::EM101) {
|
||||
if string.len() > checker.settings.flake8_errmsg.max_string_length {
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
violations::RawStringInException,
|
||||
@@ -26,7 +26,7 @@ pub fn string_in_exception(checker: &mut Checker, exc: &Expr) {
|
||||
}
|
||||
// Check for f-strings
|
||||
ExprKind::JoinedStr { .. } => {
|
||||
if checker.settings.enabled.contains(&RuleCode::EM102) {
|
||||
if checker.settings.rules.enabled(&RuleCode::EM102) {
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
violations::FStringInException,
|
||||
Range::from_located(first),
|
||||
@@ -35,7 +35,7 @@ pub fn string_in_exception(checker: &mut Checker, exc: &Expr) {
|
||||
}
|
||||
// Check for .format() calls
|
||||
ExprKind::Call { func, .. } => {
|
||||
if checker.settings.enabled.contains(&RuleCode::EM103) {
|
||||
if checker.settings.rules.enabled(&RuleCode::EM103) {
|
||||
if let ExprKind::Attribute { value, attr, .. } = &func.node {
|
||||
if attr == "format" && matches!(value.node, ExprKind::Constant { .. }) {
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
//! Rules from [flake8-implicit-str-concat](https://pypi.org/project/flake8-implicit-str-concat/0.3.0/).
|
||||
pub(crate) mod rules;
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
//! Rules from [flake8-import-conventions](https://github.com/joaopalmeiro/flake8-import-conventions).
|
||||
pub(crate) mod rules;
|
||||
pub mod settings;
|
||||
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
//! Settings for import conventions.
|
||||
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::hash::Hash;
|
||||
|
||||
use itertools::Itertools;
|
||||
use ruff_macros::ConfigurationOptions;
|
||||
use rustc_hash::FxHashMap;
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::settings::hashable::HashableHashMap;
|
||||
|
||||
const CONVENTIONAL_ALIASES: &[(&str, &str)] = &[
|
||||
("altair", "alt"),
|
||||
("matplotlib.pyplot", "plt"),
|
||||
@@ -55,17 +56,9 @@ pub struct Options {
|
||||
pub extend_aliases: Option<FxHashMap<String, String>>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Hash)]
|
||||
pub struct Settings {
|
||||
pub aliases: FxHashMap<String, String>,
|
||||
}
|
||||
|
||||
impl Hash for Settings {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
for value in self.aliases.iter().sorted() {
|
||||
value.hash(state);
|
||||
}
|
||||
}
|
||||
pub aliases: HashableHashMap<String, String>,
|
||||
}
|
||||
|
||||
fn default_aliases() -> FxHashMap<String, String> {
|
||||
@@ -89,7 +82,7 @@ fn resolve_aliases(options: Options) -> FxHashMap<String, String> {
|
||||
impl Default for Settings {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
aliases: default_aliases(),
|
||||
aliases: default_aliases().into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -97,7 +90,7 @@ impl Default for Settings {
|
||||
impl From<Options> for Settings {
|
||||
fn from(options: Options) -> Self {
|
||||
Self {
|
||||
aliases: resolve_aliases(options),
|
||||
aliases: resolve_aliases(options).into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -105,7 +98,7 @@ impl From<Options> for Settings {
|
||||
impl From<Settings> for Options {
|
||||
fn from(settings: Settings) -> Self {
|
||||
Self {
|
||||
aliases: Some(settings.aliases),
|
||||
aliases: Some(settings.aliases.into()),
|
||||
extend_aliases: None,
|
||||
}
|
||||
}
|
||||
|
||||
32
src/rules/flake8_no_pep420/mod.rs
Normal file
32
src/rules/flake8_no_pep420/mod.rs
Normal file
@@ -0,0 +1,32 @@
|
||||
//! Rules from [flake8-no-pep420](https://pypi.org/project/flake8-boolean-trap/2.3.0/).
|
||||
pub(crate) mod rules;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::path::Path;
|
||||
|
||||
use anyhow::Result;
|
||||
use test_case::test_case;
|
||||
|
||||
use crate::linter::test_path;
|
||||
use crate::registry::RuleCode;
|
||||
use crate::settings::Settings;
|
||||
|
||||
#[test_case(Path::new("test_pass"); "INP001_0")]
|
||||
#[test_case(Path::new("test_fail_empty"); "INP001_1")]
|
||||
#[test_case(Path::new("test_fail_nonempty"); "INP001_2")]
|
||||
#[test_case(Path::new("test_fail_shebang"); "INP001_3")]
|
||||
#[test_case(Path::new("test_ignored"); "INP001_4")]
|
||||
fn test_flake8_no_pep420(path: &Path) -> Result<()> {
|
||||
let snapshot = format!("{}", path.to_string_lossy());
|
||||
let diagnostics = test_path(
|
||||
Path::new("./resources/test/fixtures/flake8_no_pep420")
|
||||
.join(path)
|
||||
.join("example.py")
|
||||
.as_path(),
|
||||
&Settings::for_rule(RuleCode::INP001),
|
||||
)?;
|
||||
insta::assert_yaml_snapshot!(snapshot, diagnostics);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
18
src/rules/flake8_no_pep420/rules.rs
Normal file
18
src/rules/flake8_no_pep420/rules.rs
Normal file
@@ -0,0 +1,18 @@
|
||||
use std::path::Path;
|
||||
|
||||
use crate::ast::types::Range;
|
||||
use crate::registry::Diagnostic;
|
||||
use crate::violations;
|
||||
|
||||
/// INP001
|
||||
pub fn implicit_namespace_package(path: &Path) -> Option<Diagnostic> {
|
||||
if let Some(parent) = path.parent() {
|
||||
if !parent.join("__init__.py").as_path().exists() {
|
||||
return Some(Diagnostic::new(
|
||||
violations::ImplicitNamespacePackage(path.to_string_lossy().to_string()),
|
||||
Range::default(),
|
||||
));
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
---
|
||||
source: src/rules/flake8_no_pep420/mod.rs
|
||||
expression: diagnostics
|
||||
---
|
||||
- kind:
|
||||
ImplicitNamespacePackage: "./resources/test/fixtures/flake8_no_pep420/test_fail_empty/example.py"
|
||||
location:
|
||||
row: 1
|
||||
column: 0
|
||||
end_location:
|
||||
row: 1
|
||||
column: 0
|
||||
fix: ~
|
||||
parent: ~
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
---
|
||||
source: src/rules/flake8_no_pep420/mod.rs
|
||||
expression: diagnostics
|
||||
---
|
||||
- kind:
|
||||
ImplicitNamespacePackage: "./resources/test/fixtures/flake8_no_pep420/test_fail_nonempty/example.py"
|
||||
location:
|
||||
row: 1
|
||||
column: 0
|
||||
end_location:
|
||||
row: 1
|
||||
column: 0
|
||||
fix: ~
|
||||
parent: ~
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
---
|
||||
source: src/rules/flake8_no_pep420/mod.rs
|
||||
expression: diagnostics
|
||||
---
|
||||
- kind:
|
||||
ImplicitNamespacePackage: "./resources/test/fixtures/flake8_no_pep420/test_fail_shebang/example.py"
|
||||
location:
|
||||
row: 1
|
||||
column: 0
|
||||
end_location:
|
||||
row: 1
|
||||
column: 0
|
||||
fix: ~
|
||||
parent: ~
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
source: src/rules/flake8_no_pep420/mod.rs
|
||||
expression: diagnostics
|
||||
---
|
||||
[]
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
source: src/rules/flake8_no_pep420/mod.rs
|
||||
expression: diagnostics
|
||||
---
|
||||
[]
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
//! Rules from [flake8-pie](https://pypi.org/project/flake8-pie/0.16.0/).
|
||||
pub(crate) mod rules;
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -14,6 +15,7 @@ mod tests {
|
||||
|
||||
#[test_case(RuleCode::PIE790, Path::new("PIE790.py"); "PIE790")]
|
||||
#[test_case(RuleCode::PIE794, Path::new("PIE794.py"); "PIE794")]
|
||||
#[test_case(RuleCode::PIE796, Path::new("PIE796.py"); "PIE796")]
|
||||
#[test_case(RuleCode::PIE807, Path::new("PIE807.py"); "PIE807")]
|
||||
fn rules(rule_code: RuleCode, path: &Path) -> Result<()> {
|
||||
let snapshot = format!("{}_{}", rule_code.as_ref(), path.to_string_lossy());
|
||||
|
||||
@@ -2,6 +2,8 @@ use log::error;
|
||||
use rustc_hash::FxHashSet;
|
||||
use rustpython_ast::{Constant, Expr, ExprKind, Stmt, StmtKind};
|
||||
|
||||
use crate::ast::comparable::ComparableExpr;
|
||||
use crate::ast::helpers::unparse_expr;
|
||||
use crate::ast::types::{Range, RefEquality};
|
||||
use crate::autofix::helpers::delete_stmt;
|
||||
use crate::checkers::ast::Checker;
|
||||
@@ -106,6 +108,50 @@ pub fn dupe_class_field_definitions<'a, 'b>(
|
||||
}
|
||||
}
|
||||
|
||||
/// PIE796
|
||||
pub fn prefer_unique_enums<'a, 'b>(checker: &mut Checker<'a>, parent: &'b Stmt, body: &'b [Stmt])
|
||||
where
|
||||
'b: 'a,
|
||||
{
|
||||
let StmtKind::ClassDef { bases, .. } = &parent.node else {
|
||||
return;
|
||||
};
|
||||
|
||||
if !bases.iter().any(|expr| {
|
||||
checker
|
||||
.resolve_call_path(expr)
|
||||
.map_or(false, |call_path| call_path == ["enum", "Enum"])
|
||||
}) {
|
||||
return;
|
||||
}
|
||||
|
||||
let mut seen_targets: FxHashSet<ComparableExpr> = FxHashSet::default();
|
||||
for stmt in body {
|
||||
let StmtKind::Assign { value, .. } = &stmt.node else {
|
||||
continue;
|
||||
};
|
||||
|
||||
if let ExprKind::Call { func, .. } = &value.node {
|
||||
if checker
|
||||
.resolve_call_path(func)
|
||||
.map_or(false, |call_path| call_path == ["enum", "auto"])
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if !seen_targets.insert(ComparableExpr::from(value)) {
|
||||
let diagnostic = Diagnostic::new(
|
||||
violations::PreferUniqueEnums {
|
||||
value: unparse_expr(value, checker.stylist),
|
||||
},
|
||||
Range::from_located(stmt),
|
||||
);
|
||||
checker.diagnostics.push(diagnostic);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// PIE807
|
||||
pub fn prefer_list_builtin(checker: &mut Checker, expr: &Expr) {
|
||||
let ExprKind::Lambda { args, body } = &expr.node else {
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
---
|
||||
source: src/rules/flake8_pie/mod.rs
|
||||
expression: diagnostics
|
||||
---
|
||||
- kind:
|
||||
PreferUniqueEnums:
|
||||
value: "\"B\""
|
||||
location:
|
||||
row: 8
|
||||
column: 4
|
||||
end_location:
|
||||
row: 8
|
||||
column: 11
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
PreferUniqueEnums:
|
||||
value: "2"
|
||||
location:
|
||||
row: 14
|
||||
column: 4
|
||||
end_location:
|
||||
row: 14
|
||||
column: 9
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
PreferUniqueEnums:
|
||||
value: "\"2\""
|
||||
location:
|
||||
row: 20
|
||||
column: 4
|
||||
end_location:
|
||||
row: 20
|
||||
column: 11
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
PreferUniqueEnums:
|
||||
value: "2.5"
|
||||
location:
|
||||
row: 26
|
||||
column: 4
|
||||
end_location:
|
||||
row: 26
|
||||
column: 11
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
PreferUniqueEnums:
|
||||
value: "False"
|
||||
location:
|
||||
row: 33
|
||||
column: 4
|
||||
end_location:
|
||||
row: 33
|
||||
column: 13
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
PreferUniqueEnums:
|
||||
value: None
|
||||
location:
|
||||
row: 40
|
||||
column: 4
|
||||
end_location:
|
||||
row: 40
|
||||
column: 12
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
PreferUniqueEnums:
|
||||
value: "2"
|
||||
location:
|
||||
row: 54
|
||||
column: 4
|
||||
end_location:
|
||||
row: 54
|
||||
column: 9
|
||||
fix: ~
|
||||
parent: ~
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
//! Rules from [flake8-print](https://pypi.org/project/flake8-print/5.0.0/).
|
||||
pub(crate) mod rules;
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user