Compare commits
55 Commits
useless_re
...
v0.0.258
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
615887a7fe | ||
|
|
07808a58f2 | ||
|
|
fe568c08d2 | ||
|
|
7741d43ae5 | ||
|
|
1b3e54231c | ||
|
|
3a8e98341b | ||
|
|
8593739f88 | ||
|
|
242dd3dae1 | ||
|
|
875f61cb62 | ||
|
|
3ec1ea8ac2 | ||
|
|
1e45b13958 | ||
|
|
9e61956711 | ||
|
|
5eae3fbbfb | ||
|
|
41e38ffa98 | ||
|
|
27903cdb11 | ||
|
|
3b1709ba1e | ||
|
|
33394e4a69 | ||
|
|
7b9bdc494a | ||
|
|
b06ca25421 | ||
|
|
c42f8b93d2 | ||
|
|
f59a22b6e5 | ||
|
|
b5edc6dfc9 | ||
|
|
626169e2ef | ||
|
|
e9f359ac5e | ||
|
|
318c2c80e2 | ||
|
|
92aa3a8178 | ||
|
|
22a4ab51f9 | ||
|
|
f70a49ed8b | ||
|
|
f039bf36a2 | ||
|
|
169dd72328 | ||
|
|
fd39ec4bdd | ||
|
|
7c0f17279c | ||
|
|
81d0884974 | ||
|
|
a45753f462 | ||
|
|
b08326162b | ||
|
|
3a65af4dae | ||
|
|
474aa0b196 | ||
|
|
4892167217 | ||
|
|
a5494b8541 | ||
|
|
9ac9a1c69e | ||
|
|
f06dff8af8 | ||
|
|
fe7443ce2f | ||
|
|
4bdb2dd362 | ||
|
|
53a4743631 | ||
|
|
4ffcd8366a | ||
|
|
dfb772c6f1 | ||
|
|
c21eb06922 | ||
|
|
16a350c731 | ||
|
|
fa04861724 | ||
|
|
404504ab41 | ||
|
|
621e4353e3 | ||
|
|
0c4926ff7b | ||
|
|
61653b9f27 | ||
|
|
8dd3959e74 | ||
|
|
50f9db21da |
96
.github/workflows/benchmark.yaml
vendored
96
.github/workflows/benchmark.yaml
vendored
@@ -26,7 +26,7 @@ jobs:
|
||||
- name: "PR - Install Rust toolchain"
|
||||
run: rustup show
|
||||
|
||||
- uses: Swatinem/rust-cache@v1
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
|
||||
- name: "PR - Build benchmarks"
|
||||
uses: actions-rs/cargo@v1
|
||||
@@ -75,59 +75,61 @@ jobs:
|
||||
- run-benchmark
|
||||
|
||||
steps:
|
||||
- name: "Install Rust toolchain"
|
||||
run: rustup show
|
||||
- name: "Install Rust toolchain"
|
||||
run: rustup show
|
||||
|
||||
- name: "Install critcmp"
|
||||
# Use debug build: Building takes much longer than the "slowness" of using the debug build.
|
||||
run: cargo install --debug critcmp
|
||||
- name: "Install cargo-binstall"
|
||||
uses: taiki-e/install-action@cargo-binstall
|
||||
|
||||
- name: "Linux | Download PR benchmark results"
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: benchmark-results-ubuntu-latest
|
||||
path: ./target/criterion
|
||||
- name: "Install critcmp"
|
||||
run: cargo binstall critcmp -y
|
||||
|
||||
- name: "Linux | Compare benchmark results"
|
||||
shell: bash
|
||||
run: |
|
||||
echo "### Benchmark" >> summary.md
|
||||
echo "#### Linux" >> summary.md
|
||||
echo "\`\`\`" >> summary.md
|
||||
critcmp main pr >> summary.md
|
||||
echo "\`\`\`" >> summary.md
|
||||
echo "" >> summary.md
|
||||
- name: "Linux | Download PR benchmark results"
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: benchmark-results-ubuntu-latest
|
||||
path: ./target/criterion
|
||||
|
||||
- name: "Linux | Cleanup benchmark results"
|
||||
run: rm -rf ./target/criterion
|
||||
- name: "Linux | Compare benchmark results"
|
||||
shell: bash
|
||||
run: |
|
||||
echo "### Benchmark" >> summary.md
|
||||
echo "#### Linux" >> summary.md
|
||||
echo "\`\`\`" >> summary.md
|
||||
critcmp main pr >> summary.md
|
||||
echo "\`\`\`" >> summary.md
|
||||
echo "" >> summary.md
|
||||
|
||||
- name: "Windows | Download PR benchmark results"
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: benchmark-results-windows-latest
|
||||
path: ./target/criterion
|
||||
- name: "Linux | Cleanup benchmark results"
|
||||
run: rm -rf ./target/criterion
|
||||
|
||||
- name: "Windows | Compare benchmark results"
|
||||
shell: bash
|
||||
run: |
|
||||
echo "#### Windows" >> summary.md
|
||||
echo "\`\`\`" >> summary.md
|
||||
critcmp main pr >> summary.md
|
||||
echo "\`\`\`" >> summary.md
|
||||
echo "" >> summary.md
|
||||
- name: "Windows | Download PR benchmark results"
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: benchmark-results-windows-latest
|
||||
path: ./target/criterion
|
||||
|
||||
echo ${{ github.event.pull_request.number }} > pr-number
|
||||
- name: "Windows | Compare benchmark results"
|
||||
shell: bash
|
||||
run: |
|
||||
echo "#### Windows" >> summary.md
|
||||
echo "\`\`\`" >> summary.md
|
||||
critcmp main pr >> summary.md
|
||||
echo "\`\`\`" >> summary.md
|
||||
echo "" >> summary.md
|
||||
|
||||
cat summary.md > $GITHUB_STEP_SUMMARY
|
||||
echo ${{ github.event.pull_request.number }} > pr-number
|
||||
|
||||
- uses: actions/upload-artifact@v3
|
||||
name: Upload PR Number
|
||||
with:
|
||||
name: pr-number
|
||||
path: pr-number
|
||||
cat summary.md > $GITHUB_STEP_SUMMARY
|
||||
|
||||
- uses: actions/upload-artifact@v3
|
||||
name: Upload Summary
|
||||
with:
|
||||
name: summary
|
||||
path: summary.md
|
||||
- uses: actions/upload-artifact@v3
|
||||
name: Upload PR Number
|
||||
with:
|
||||
name: pr-number
|
||||
path: pr-number
|
||||
|
||||
- uses: actions/upload-artifact@v3
|
||||
name: Upload Summary
|
||||
with:
|
||||
name: summary
|
||||
path: summary.md
|
||||
|
||||
24
.github/workflows/ci.yaml
vendored
24
.github/workflows/ci.yaml
vendored
@@ -85,7 +85,6 @@ jobs:
|
||||
name: ruff
|
||||
path: target/debug/ruff
|
||||
|
||||
|
||||
cargo-test-wasm:
|
||||
runs-on: ubuntu-latest
|
||||
name: "cargo test (wasm)"
|
||||
@@ -176,3 +175,26 @@ jobs:
|
||||
with:
|
||||
name: ecosystem-result
|
||||
path: ecosystem-result
|
||||
|
||||
cargo-udeps:
|
||||
name: "cargo udeps"
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: "Install Rust toolchain"
|
||||
run: rustup toolchain install nightly
|
||||
- name: "Install cargo-udeps"
|
||||
uses: taiki-e/install-action@cargo-udeps
|
||||
- name: "Run cargo-udeps"
|
||||
run: |
|
||||
unused_dependencies=$(cargo +nightly udeps > unused.txt && cat unused.txt | cut -d $'\n' -f 2-)
|
||||
if [ -z "$unused_dependencies" ]; then
|
||||
echo "No unused dependencies found" > $GITHUB_STEP_SUMMARY
|
||||
exit 0
|
||||
else
|
||||
echo "Unused dependencies found" > $GITHUB_STEP_SUMMARY
|
||||
echo '```console' >> $GITHUB_STEP_SUMMARY
|
||||
echo "$unused_dependencies" >> $GITHUB_STEP_SUMMARY
|
||||
echo '```' >> $GITHUB_STEP_SUMMARY
|
||||
exit 1
|
||||
fi
|
||||
|
||||
1
.github/workflows/pr-comment.yaml
vendored
1
.github/workflows/pr-comment.yaml
vendored
@@ -65,6 +65,7 @@ jobs:
|
||||
then
|
||||
echo "### Ecosystem" >> $GITHUB_OUTPUT
|
||||
cat pr/ecosystem/ecosystem-result >> $GITHUB_OUTPUT
|
||||
echo "" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
if [[ -f pr/benchmark/summary.md ]]
|
||||
|
||||
@@ -28,17 +28,17 @@ repos:
|
||||
- id: cargo-fmt
|
||||
name: cargo fmt
|
||||
entry: cargo fmt --
|
||||
language: rust
|
||||
language: system
|
||||
types: [rust]
|
||||
- id: clippy
|
||||
name: clippy
|
||||
entry: cargo clippy --workspace --all-targets --all-features -- -D warnings
|
||||
language: rust
|
||||
language: system
|
||||
pass_filenames: false
|
||||
- id: ruff
|
||||
name: ruff
|
||||
entry: cargo run -p ruff_cli -- check --no-cache --force-exclude --fix --exit-non-zero-on-fix
|
||||
language: rust
|
||||
language: system
|
||||
types_or: [python, pyi]
|
||||
require_serial: true
|
||||
exclude: |
|
||||
@@ -49,7 +49,7 @@ repos:
|
||||
- id: dev-generate-all
|
||||
name: dev-generate-all
|
||||
entry: cargo dev generate-all
|
||||
language: rust
|
||||
language: system
|
||||
pass_filenames: false
|
||||
exclude: target
|
||||
|
||||
|
||||
@@ -145,4 +145,4 @@ default.
|
||||
`pyproject.toml` files are now resolved hierarchically, such that for each Python file, we find
|
||||
the first `pyproject.toml` file in its path, and use that to determine its lint settings.
|
||||
|
||||
See the [README](https://github.com/charliermarsh/ruff#pyprojecttoml-discovery) for more.
|
||||
See the [documentation](https://beta.ruff.rs/docs/configuration/#python-file-discovery) for more.
|
||||
|
||||
11
Cargo.lock
generated
11
Cargo.lock
generated
@@ -780,7 +780,7 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
|
||||
|
||||
[[package]]
|
||||
name = "flake8-to-ruff"
|
||||
version = "0.0.256"
|
||||
version = "0.0.258"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap 4.1.8",
|
||||
@@ -1982,7 +1982,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ruff"
|
||||
version = "0.0.256"
|
||||
version = "0.0.258"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bisection",
|
||||
@@ -1990,7 +1990,6 @@ dependencies = [
|
||||
"chrono",
|
||||
"clap 4.1.8",
|
||||
"colored",
|
||||
"criterion",
|
||||
"dirs",
|
||||
"fern",
|
||||
"glob",
|
||||
@@ -2025,6 +2024,7 @@ dependencies = [
|
||||
"schemars",
|
||||
"semver",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"shellexpand",
|
||||
"smallvec",
|
||||
"strum",
|
||||
@@ -2063,7 +2063,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ruff_cli"
|
||||
version = "0.0.256"
|
||||
version = "0.0.258"
|
||||
dependencies = [
|
||||
"annotate-snippets 0.9.1",
|
||||
"anyhow",
|
||||
@@ -2091,6 +2091,7 @@ dependencies = [
|
||||
"ruff",
|
||||
"ruff_cache",
|
||||
"ruff_diagnostics",
|
||||
"ruff_python_stdlib",
|
||||
"rustc-hash",
|
||||
"serde",
|
||||
"serde_json",
|
||||
@@ -2210,7 +2211,6 @@ name = "ruff_python_stdlib"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"regex",
|
||||
"rustc-hash",
|
||||
]
|
||||
|
||||
@@ -2505,6 +2505,7 @@ version = "1.0.93"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cad406b69c91885b5107daf2c29572f6c8cdb3c66826821e286c533490c0bc76"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"itoa",
|
||||
"ryu",
|
||||
"serde",
|
||||
|
||||
@@ -37,7 +37,7 @@ rustpython-parser = { features = [
|
||||
], git = "https://github.com/RustPython/RustPython.git", rev = "c15f670f2c30cfae6b41a1874893590148c74bc4" }
|
||||
schemars = { version = "0.8.12" }
|
||||
serde = { version = "1.0.152", features = ["derive"] }
|
||||
serde_json = { version = "1.0.93" }
|
||||
serde_json = { version = "1.0.93", features = ["preserve_order"] }
|
||||
shellexpand = { version = "3.0.0" }
|
||||
similar = { version = "2.2.1" }
|
||||
strum = { version = "0.24.1", features = ["strum_macros"] }
|
||||
@@ -48,8 +48,7 @@ textwrap = { version = "0.16.0" }
|
||||
toml = { version = "0.7.2" }
|
||||
|
||||
[profile.release]
|
||||
panic = "abort"
|
||||
lto = "thin"
|
||||
lto = "fat"
|
||||
codegen-units = 1
|
||||
opt-level = 3
|
||||
|
||||
|
||||
26
LICENSE
26
LICENSE
@@ -393,7 +393,6 @@ are:
|
||||
THE SOFTWARE.
|
||||
"""
|
||||
|
||||
|
||||
- autoflake, licensed as follows:
|
||||
"""
|
||||
Copyright (C) 2012-2018 Steven Myint
|
||||
@@ -417,6 +416,31 @@ are:
|
||||
SOFTWARE.
|
||||
"""
|
||||
|
||||
- autotyping, licensed as follows:
|
||||
"""
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2023 Jelle Zijlstra
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
"""
|
||||
|
||||
- Flake8, licensed as follows:
|
||||
"""
|
||||
== Flake8 License (MIT) ==
|
||||
|
||||
51
README.md
51
README.md
@@ -137,7 +137,7 @@ Ruff can also be used as a [pre-commit](https://pre-commit.com) hook:
|
||||
```yaml
|
||||
- repo: https://github.com/charliermarsh/ruff-pre-commit
|
||||
# Ruff version.
|
||||
rev: 'v0.0.256'
|
||||
rev: 'v0.0.258'
|
||||
hooks:
|
||||
- id: ruff
|
||||
```
|
||||
@@ -227,6 +227,54 @@ stylistic rules made obsolete by the use of an autoformatter, like
|
||||
If you're just getting started with Ruff, **the default rule set is a great place to start**: it
|
||||
catches a wide variety of common errors (like unused imports) with zero configuration.
|
||||
|
||||
Beyond the defaults, Ruff re-implements some of the most popular Flake8 plugins and related code
|
||||
quality tools, including:
|
||||
|
||||
- [autoflake](https://pypi.org/project/autoflake/)
|
||||
- [eradicate](https://pypi.org/project/eradicate/)
|
||||
- [flake8-2020](https://pypi.org/project/flake8-2020/)
|
||||
- [flake8-annotations](https://pypi.org/project/flake8-annotations/)
|
||||
- [flake8-bandit](https://pypi.org/project/flake8-bandit/) ([#1646](https://github.com/charliermarsh/ruff/issues/1646))
|
||||
- [flake8-blind-except](https://pypi.org/project/flake8-blind-except/)
|
||||
- [flake8-boolean-trap](https://pypi.org/project/flake8-boolean-trap/)
|
||||
- [flake8-bugbear](https://pypi.org/project/flake8-bugbear/)
|
||||
- [flake8-builtins](https://pypi.org/project/flake8-builtins/)
|
||||
- [flake8-commas](https://pypi.org/project/flake8-commas/)
|
||||
- [flake8-comprehensions](https://pypi.org/project/flake8-comprehensions/)
|
||||
- [flake8-datetimez](https://pypi.org/project/flake8-datetimez/)
|
||||
- [flake8-debugger](https://pypi.org/project/flake8-debugger/)
|
||||
- [flake8-django](https://pypi.org/project/flake8-django/)
|
||||
- [flake8-docstrings](https://pypi.org/project/flake8-docstrings/)
|
||||
- [flake8-eradicate](https://pypi.org/project/flake8-eradicate/)
|
||||
- [flake8-errmsg](https://pypi.org/project/flake8-errmsg/)
|
||||
- [flake8-executable](https://pypi.org/project/flake8-executable/)
|
||||
- [flake8-implicit-str-concat](https://pypi.org/project/flake8-implicit-str-concat/)
|
||||
- [flake8-import-conventions](https://github.com/joaopalmeiro/flake8-import-conventions)
|
||||
- [flake8-logging-format](https://pypi.org/project/flake8-logging-format/)
|
||||
- [flake8-no-pep420](https://pypi.org/project/flake8-no-pep420)
|
||||
- [flake8-pie](https://pypi.org/project/flake8-pie/)
|
||||
- [flake8-print](https://pypi.org/project/flake8-print/)
|
||||
- [flake8-pyi](https://pypi.org/project/flake8-pyi/)
|
||||
- [flake8-pytest-style](https://pypi.org/project/flake8-pytest-style/)
|
||||
- [flake8-quotes](https://pypi.org/project/flake8-quotes/)
|
||||
- [flake8-raise](https://pypi.org/project/flake8-raise/)
|
||||
- [flake8-return](https://pypi.org/project/flake8-return/)
|
||||
- [flake8-self](https://pypi.org/project/flake8-self/)
|
||||
- [flake8-simplify](https://pypi.org/project/flake8-simplify/)
|
||||
- [flake8-super](https://pypi.org/project/flake8-super/)
|
||||
- [flake8-tidy-imports](https://pypi.org/project/flake8-tidy-imports/)
|
||||
- [flake8-type-checking](https://pypi.org/project/flake8-type-checking/)
|
||||
- [flake8-use-pathlib](https://pypi.org/project/flake8-use-pathlib/)
|
||||
- [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))
|
||||
- [pyupgrade](https://pypi.org/project/pyupgrade/)
|
||||
- [tryceratops](https://pypi.org/project/tryceratops/)
|
||||
- [yesqa](https://pypi.org/project/yesqa/)
|
||||
|
||||
<!-- End section: Rules -->
|
||||
|
||||
For a complete enumeration of the supported rules, see [_Rules_](https://beta.ruff.rs/docs/rules/).
|
||||
@@ -280,6 +328,7 @@ Ruff is used in a number of major open-source projects, including:
|
||||
- [Zulip](https://github.com/zulip/zulip)
|
||||
- [Bokeh](https://github.com/bokeh/bokeh)
|
||||
- [Pydantic](https://github.com/pydantic/pydantic)
|
||||
- [PostHog](https://github.com/PostHog/posthog)
|
||||
- [Dagster](https://github.com/dagster-io/dagster)
|
||||
- [Dagger](https://github.com/dagger/dagger)
|
||||
- [Sphinx](https://github.com/sphinx-doc/sphinx)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "flake8-to-ruff"
|
||||
version = "0.0.256"
|
||||
version = "0.0.258"
|
||||
edition = { workspace = true }
|
||||
rust-version = { workspace = true }
|
||||
|
||||
|
||||
@@ -85,8 +85,9 @@ flake8-to-ruff path/to/.flake8 --plugin flake8-builtins --plugin flake8-quotes
|
||||
ignore unsupported options in the `.flake8` file (or equivalent). (Similarly, Ruff has a few
|
||||
configuration options that don't exist in Flake8.)
|
||||
1. Ruff will omit any rule codes that are unimplemented or unsupported by Ruff, including rule
|
||||
codes from unsupported plugins. (See the [Ruff README](https://github.com/charliermarsh/ruff#user-content-how-does-ruff-compare-to-flake8)
|
||||
for the complete list of supported plugins.)
|
||||
codes from unsupported plugins. (See the
|
||||
[documentation](https://beta.ruff.rs/docs/faq/#how-does-ruff-compare-to-flake8) for the complete
|
||||
list of supported plugins.)
|
||||
|
||||
## License
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "ruff"
|
||||
version = "0.0.256"
|
||||
version = "0.0.258"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
rust-version.workspace = true
|
||||
@@ -65,13 +65,13 @@ strum_macros = { workspace = true }
|
||||
textwrap = { workspace = true }
|
||||
thiserror = { version = "1.0.38" }
|
||||
toml = { workspace = true }
|
||||
serde_json = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
criterion = { version = "0.4.0" }
|
||||
insta = { workspace = true, features = ["yaml", "redactions"] }
|
||||
pretty_assertions = "1.3.0"
|
||||
test-case = { workspace = true }
|
||||
|
||||
[features]
|
||||
default = []
|
||||
logical_lines = []
|
||||
jupyter_notebook = []
|
||||
|
||||
@@ -2,3 +2,7 @@ avoid-*
|
||||
do-not-*
|
||||
uses-*
|
||||
*-used
|
||||
rewrite-*
|
||||
prefer-*
|
||||
consider-*
|
||||
use-*
|
||||
|
||||
42
crates/ruff/resources/test/fixtures/flake8_annotations/simple_magic_methods.py
vendored
Normal file
42
crates/ruff/resources/test/fixtures/flake8_annotations/simple_magic_methods.py
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
class Foo:
|
||||
def __str__(self):
|
||||
...
|
||||
|
||||
def __repr__(self):
|
||||
...
|
||||
|
||||
def __len__(self):
|
||||
...
|
||||
|
||||
def __length_hint__(self):
|
||||
...
|
||||
|
||||
def __init__(self):
|
||||
...
|
||||
|
||||
def __del__(self):
|
||||
...
|
||||
|
||||
def __bool__(self):
|
||||
...
|
||||
|
||||
def __bytes__(self):
|
||||
...
|
||||
|
||||
def __format__(self, format_spec):
|
||||
...
|
||||
|
||||
def __contains__(self, item):
|
||||
...
|
||||
|
||||
def __complex__(self):
|
||||
...
|
||||
|
||||
def __int__(self):
|
||||
...
|
||||
|
||||
def __float__(self):
|
||||
...
|
||||
|
||||
def __index__(self):
|
||||
...
|
||||
3
crates/ruff/resources/test/fixtures/flake8_bandit/S301.py
vendored
Normal file
3
crates/ruff/resources/test/fixtures/flake8_bandit/S301.py
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
import pickle
|
||||
|
||||
pickle.loads()
|
||||
3
crates/ruff/resources/test/fixtures/flake8_bandit/S312.py
vendored
Normal file
3
crates/ruff/resources/test/fixtures/flake8_bandit/S312.py
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
from telnetlib import Telnet
|
||||
|
||||
Telnet("localhost", 23)
|
||||
@@ -1,6 +1,19 @@
|
||||
x = [1, 2, 3]
|
||||
y = [("a", 1), ("b", 2), ("c", 3)]
|
||||
z = [(1,), (2,), (3,)]
|
||||
d = {"a": 1, "b": 2, "c": 3}
|
||||
|
||||
[i for i in x]
|
||||
{i for i in x}
|
||||
{k: v for k, v in y}
|
||||
{k: v for k, v in d.items()}
|
||||
|
||||
[i for i, in z]
|
||||
[i for i, j in y]
|
||||
[i for i in x if i > 1]
|
||||
[i for i in x for j in x]
|
||||
|
||||
{v: k for k, v in y}
|
||||
{k.foo: k for k in y}
|
||||
{k["foo"]: k for k in y}
|
||||
{k: v if v else None for k, v in y}
|
||||
|
||||
113
crates/ruff/resources/test/fixtures/flake8_django/DJ012.py
vendored
Normal file
113
crates/ruff/resources/test/fixtures/flake8_django/DJ012.py
vendored
Normal file
@@ -0,0 +1,113 @@
|
||||
from django.db import models
|
||||
from django.db.models import Model
|
||||
|
||||
|
||||
class StrBeforeRandomField(models.Model):
|
||||
"""Model with `__str__` before a random property."""
|
||||
|
||||
class Meta:
|
||||
verbose_name = "test"
|
||||
verbose_name_plural = "tests"
|
||||
|
||||
def __str__(self):
|
||||
return ""
|
||||
|
||||
random_property = "foo"
|
||||
|
||||
|
||||
class StrBeforeFieldModel(models.Model):
|
||||
"""Model with `__str__` before fields."""
|
||||
|
||||
class Meta:
|
||||
verbose_name = "test"
|
||||
verbose_name_plural = "tests"
|
||||
|
||||
def __str__(self):
|
||||
return "foobar"
|
||||
|
||||
first_name = models.CharField(max_length=32)
|
||||
|
||||
|
||||
class ManagerBeforeField(models.Model):
|
||||
"""Model with manager before fields."""
|
||||
|
||||
objects = "manager"
|
||||
|
||||
class Meta:
|
||||
verbose_name = "test"
|
||||
verbose_name_plural = "tests"
|
||||
|
||||
def __str__(self):
|
||||
return "foobar"
|
||||
|
||||
first_name = models.CharField(max_length=32)
|
||||
|
||||
|
||||
class CustomMethodBeforeStr(models.Model):
|
||||
"""Model with a custom method before `__str__`."""
|
||||
|
||||
class Meta:
|
||||
verbose_name = "test"
|
||||
verbose_name_plural = "tests"
|
||||
|
||||
def my_method(self):
|
||||
pass
|
||||
|
||||
def __str__(self):
|
||||
return "foobar"
|
||||
|
||||
|
||||
class GetAbsoluteUrlBeforeSave(Model):
|
||||
"""Model with `get_absolute_url` method before `save` method.
|
||||
|
||||
Subclass this directly using the `Model` class.
|
||||
"""
|
||||
|
||||
def get_absolute_url(self):
|
||||
pass
|
||||
|
||||
def save(self):
|
||||
pass
|
||||
|
||||
|
||||
class ConstantsAreNotFields(models.Model):
|
||||
"""Model with an assignment to a constant after `__str__`."""
|
||||
|
||||
first_name = models.CharField(max_length=32)
|
||||
|
||||
class Meta:
|
||||
verbose_name = "test"
|
||||
verbose_name_plural = "tests"
|
||||
|
||||
def __str__(self):
|
||||
pass
|
||||
|
||||
MY_CONSTANT = id(1)
|
||||
|
||||
|
||||
class PerfectlyFine(models.Model):
|
||||
"""Model which has everything in perfect order."""
|
||||
|
||||
first_name = models.CharField(max_length=32)
|
||||
last_name = models.CharField(max_length=32)
|
||||
objects = "manager"
|
||||
|
||||
class Meta:
|
||||
verbose_name = "test"
|
||||
verbose_name_plural = "tests"
|
||||
|
||||
def __str__(self):
|
||||
return "Perfectly fine!"
|
||||
|
||||
def save(self, **kwargs):
|
||||
super(PerfectlyFine, self).save(**kwargs)
|
||||
|
||||
def get_absolute_url(self):
|
||||
return "http://%s" % self
|
||||
|
||||
def my_method(self):
|
||||
pass
|
||||
|
||||
@property
|
||||
def random_property(self):
|
||||
return "%s" % self
|
||||
@@ -2,7 +2,9 @@ from a import a1 # import_from
|
||||
from c import * # import_from_star
|
||||
import a # import
|
||||
import c.d
|
||||
from z import z1
|
||||
import b as b1 # import_as
|
||||
import z
|
||||
|
||||
from ..parent import *
|
||||
from .my import fn
|
||||
|
||||
32
crates/ruff/resources/test/fixtures/jupyter/R.ipynb
vendored
Normal file
32
crates/ruff/resources/test/fixtures/jupyter/R.ipynb
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"print(paste(\"Hello\",\"WoRld\"))\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "R",
|
||||
"language": "R",
|
||||
"name": "ir"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": "r",
|
||||
"file_extension": ".r",
|
||||
"mimetype": "text/x-r-source",
|
||||
"name": "R",
|
||||
"pygments_lexer": "r",
|
||||
"version": "3.2.3"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 2
|
||||
}
|
||||
24
crates/ruff/resources/test/fixtures/jupyter/invalid_extension.ipynb
vendored
Normal file
24
crates/ruff/resources/test/fixtures/jupyter/invalid_extension.ipynb
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
#!/usr/bin/env python
|
||||
# coding: utf-8
|
||||
|
||||
# In[1]:
|
||||
|
||||
|
||||
def unused_variable():
|
||||
x = 1
|
||||
y = 2
|
||||
print(f"cell one: {y}")
|
||||
|
||||
unused_variable()
|
||||
|
||||
|
||||
# Let's do another mistake
|
||||
|
||||
# In[2]:
|
||||
|
||||
|
||||
def mutable_argument(z=set()):
|
||||
print(f"cell two: {z}")
|
||||
|
||||
mutable_argument()
|
||||
|
||||
1
crates/ruff/resources/test/fixtures/jupyter/not_json.ipynb
vendored
Normal file
1
crates/ruff/resources/test/fixtures/jupyter/not_json.ipynb
vendored
Normal file
@@ -0,0 +1 @@
|
||||
broken "§=($/=(")
|
||||
88
crates/ruff/resources/test/fixtures/jupyter/valid.ipynb
vendored
Normal file
88
crates/ruff/resources/test/fixtures/jupyter/valid.ipynb
vendored
Normal file
@@ -0,0 +1,88 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"cell one: 2\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"def unused_variable():\n",
|
||||
" x = 1\n",
|
||||
" y = 2\n",
|
||||
" print(f\"cell one: {y}\")\n",
|
||||
"\n",
|
||||
"unused_variable()"
|
||||
],
|
||||
"metadata": {
|
||||
"collapsed": false,
|
||||
"ExecuteTime": {
|
||||
"start_time": "2023-03-08T23:01:09.705831Z",
|
||||
"end_time": "2023-03-08T23:01:09.782916Z"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"Let's do another mistake"
|
||||
],
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"metadata": {
|
||||
"collapsed": true,
|
||||
"ExecuteTime": {
|
||||
"start_time": "2023-03-08T23:01:09.733809Z",
|
||||
"end_time": "2023-03-08T23:01:09.915760Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"cell two: set()\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"def mutable_argument(z=set()):\n",
|
||||
" print(f\"cell two: {z}\")\n",
|
||||
"\n",
|
||||
"mutable_argument()\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 2
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython2",
|
||||
"version": "2.7.6"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 0
|
||||
}
|
||||
1
crates/ruff/resources/test/fixtures/jupyter/wrong_schema.ipynb
vendored
Normal file
1
crates/ruff/resources/test/fixtures/jupyter/wrong_schema.ipynb
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{}
|
||||
@@ -13,3 +13,8 @@ result = {
|
||||
'key1': 'value',
|
||||
'key2': 'value',
|
||||
}
|
||||
|
||||
def foo() -> None:
|
||||
#: E231
|
||||
if (1,2):
|
||||
pass
|
||||
|
||||
@@ -113,3 +113,13 @@ def f(x, *args, **kwargs):
|
||||
**kwargs: keyword arguments
|
||||
"""
|
||||
return x
|
||||
|
||||
|
||||
class Test:
|
||||
def f(self, /, arg1: int) -> None:
|
||||
"""
|
||||
Some beauty description.
|
||||
|
||||
Args:
|
||||
arg1: some description of arg
|
||||
"""
|
||||
|
||||
@@ -504,3 +504,12 @@ Testing this incorrectly indented docstring.
|
||||
x: Test argument.
|
||||
|
||||
"""
|
||||
|
||||
|
||||
def implicit_string_concatenation():
|
||||
"""Toggle the gizmo.
|
||||
|
||||
Returns
|
||||
A value of some sort.
|
||||
|
||||
""""Extra content"
|
||||
|
||||
@@ -1,10 +1,19 @@
|
||||
"""Test: imports within `ModuleNotFoundError` handlers."""
|
||||
"""Test: imports within `ModuleNotFoundError` and `ImportError` handlers."""
|
||||
|
||||
|
||||
def check_orjson():
|
||||
def module_not_found_error():
|
||||
try:
|
||||
import orjson
|
||||
|
||||
return True
|
||||
except ModuleNotFoundError:
|
||||
return False
|
||||
|
||||
|
||||
def import_error():
|
||||
try:
|
||||
import orjson
|
||||
|
||||
return True
|
||||
except ImportError:
|
||||
return False
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
"{1:{0}}".format(1, 2) # No issues
|
||||
"{1:{0}}".format(1, 2, 3) # F523
|
||||
"{0}{2}".format(1, 2) # F523, # F524
|
||||
"{1.arg[1]!r:0{2['arg']}{1}}".format(1, 2, 3, 4) # F523
|
||||
|
||||
# With no indexes
|
||||
"{}".format(1, 2) # F523
|
||||
|
||||
24
crates/ruff/resources/test/fixtures/pylint/assert_on_string_literal.py
vendored
Normal file
24
crates/ruff/resources/test/fixtures/pylint/assert_on_string_literal.py
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
def test_division():
|
||||
a = 9 / 3
|
||||
assert "No ZeroDivisionError were raised" # [assert-on-string-literal]
|
||||
|
||||
|
||||
def test_division():
|
||||
a = 9 / 3
|
||||
assert a == 3
|
||||
|
||||
|
||||
try:
|
||||
assert "bad" # [assert-on-string-literal]
|
||||
except:
|
||||
assert "bad again" # [assert-on-string-literal]
|
||||
|
||||
a = 12
|
||||
assert f"hello {a}" # [assert-on-string-literal]
|
||||
assert f"{a}" # [assert-on-string-literal]
|
||||
assert f"" # [assert-on-string-literal]
|
||||
assert "" # [assert-on-string-literal]
|
||||
assert b"hello" # [assert-on-string-literal]
|
||||
assert "", b"hi" # [assert-on-string-literal]
|
||||
assert "WhyNotHere?", "HereIsOk" # [assert-on-string-literal]
|
||||
assert 12, "ok here"
|
||||
14
crates/ruff/resources/test/fixtures/pylint/binary_op_exception.py
vendored
Normal file
14
crates/ruff/resources/test/fixtures/pylint/binary_op_exception.py
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
try:
|
||||
1 / 0
|
||||
except ZeroDivisionError or ValueError as e: # [binary-op-exception]
|
||||
pass
|
||||
|
||||
try:
|
||||
raise ValueError
|
||||
except ZeroDivisionError and ValueError as e: # [binary-op-exception]
|
||||
print(e)
|
||||
|
||||
try:
|
||||
pass
|
||||
except (ValueError, Exception, IOError):
|
||||
pass
|
||||
50
crates/ruff/resources/test/fixtures/pylint/useless_return.py
vendored
Normal file
50
crates/ruff/resources/test/fixtures/pylint/useless_return.py
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
import sys
|
||||
|
||||
|
||||
def print_python_version():
|
||||
print(sys.version)
|
||||
return None # [useless-return]
|
||||
|
||||
|
||||
def print_python_version():
|
||||
print(sys.version)
|
||||
return None # [useless-return]
|
||||
|
||||
|
||||
def print_python_version():
|
||||
print(sys.version)
|
||||
return None # [useless-return]
|
||||
|
||||
|
||||
class SomeClass:
|
||||
def print_python_version(self):
|
||||
print(sys.version)
|
||||
return None # [useless-return]
|
||||
|
||||
|
||||
def print_python_version():
|
||||
if 2 * 2 == 4:
|
||||
return
|
||||
print(sys.version)
|
||||
|
||||
|
||||
def print_python_version():
|
||||
if 2 * 2 == 4:
|
||||
return None
|
||||
return
|
||||
|
||||
|
||||
def print_python_version():
|
||||
if 2 * 2 == 4:
|
||||
return None
|
||||
|
||||
|
||||
def print_python_version():
|
||||
"""This function returns None."""
|
||||
return None
|
||||
|
||||
|
||||
def print_python_version():
|
||||
"""This function returns None."""
|
||||
print(sys.version)
|
||||
return None # [useless-return]
|
||||
@@ -30,8 +30,17 @@ def f(x: "List[str]") -> None:
|
||||
...
|
||||
|
||||
|
||||
list = "abc"
|
||||
|
||||
|
||||
def f(x: List[str]) -> None:
|
||||
def f(x: r"List[str]") -> None:
|
||||
...
|
||||
|
||||
|
||||
def f(x: "List[str]") -> None:
|
||||
...
|
||||
|
||||
|
||||
def f(x: """List[str]""") -> None:
|
||||
...
|
||||
|
||||
|
||||
def f(x: "Li" "st[str]") -> None:
|
||||
...
|
||||
|
||||
@@ -46,3 +46,8 @@ def f(x: Union[("str", "int"), float]) -> None:
|
||||
def f() -> None:
|
||||
x: Optional[str]
|
||||
x = Optional[str]
|
||||
|
||||
x = Union[str, int]
|
||||
x = Union["str", "int"]
|
||||
x: Union[str, int]
|
||||
x: Union["str", "int"]
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
from io import open
|
||||
|
||||
with open("f.txt") as f:
|
||||
print(f.read())
|
||||
|
||||
import io
|
||||
|
||||
with io.open("f.txt", mode="r", buffering=-1, **kwargs) as f:
|
||||
print(f.read())
|
||||
|
||||
from io import open
|
||||
|
||||
with open("f.txt") as f:
|
||||
print(f.read())
|
||||
|
||||
@@ -73,3 +73,13 @@ print("%s \N{snowman}" % (a,))
|
||||
print("%(foo)s \N{snowman}" % {"foo": 1})
|
||||
|
||||
print(("foo %s " "bar %s") % (x, y))
|
||||
|
||||
# Single-value expressions
|
||||
print('Hello %s' % "World")
|
||||
print('Hello %s' % f"World")
|
||||
print('Hello %s (%s)' % bar)
|
||||
print('Hello %s (%s)' % bar.baz)
|
||||
print('Hello %s (%s)' % bar['bop'])
|
||||
print('Hello %(arg)s' % bar)
|
||||
print('Hello %(arg)s' % bar.baz)
|
||||
print('Hello %(arg)s' % bar['bop'])
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
# OK
|
||||
"%s" % unknown_type
|
||||
|
||||
b"%s" % (b"bytestring",)
|
||||
|
||||
"%*s" % (5, "hi")
|
||||
@@ -57,3 +55,9 @@ pytest.param('"%8s" % (None,)', id="unsafe width-string conversion"),
|
||||
"""
|
||||
% (x,)
|
||||
)
|
||||
|
||||
'Hello %s' % bar
|
||||
|
||||
'Hello %s' % bar.baz
|
||||
|
||||
'Hello %s' % bar['bop']
|
||||
|
||||
@@ -86,3 +86,14 @@ async def c():
|
||||
|
||||
async def c():
|
||||
return "{}".format(1 + await 3)
|
||||
|
||||
|
||||
def d(osname, version, release):
|
||||
return"{}-{}.{}".format(osname, version, release)
|
||||
|
||||
|
||||
def e():
|
||||
yield"{}".format(1)
|
||||
|
||||
|
||||
assert"{}".format(1)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
input = [1, 2, 3]
|
||||
otherInput = [2, 3, 4]
|
||||
foo = [1, 2, 3, 4]
|
||||
|
||||
# OK
|
||||
zip(input, otherInput) # different inputs
|
||||
@@ -8,6 +9,8 @@ zip(input, input[2:]) # not successive
|
||||
zip(input[:-1], input[2:]) # not successive
|
||||
list(zip(input, otherInput)) # nested call
|
||||
zip(input, input[1::2]) # not successive
|
||||
zip(foo[:-1], foo[1:], foo, strict=False) # more than 2 inputs
|
||||
zip(foo[:-1], foo[1:], foo, strict=True) # more than 2 inputs
|
||||
|
||||
# Errors
|
||||
zip(input, input[1:])
|
||||
@@ -17,3 +20,6 @@ zip(input[1:], input[2:])
|
||||
zip(input[1:-1], input[2:])
|
||||
list(zip(input, input[1:]))
|
||||
list(zip(input[:-1], input[1:]))
|
||||
zip(foo[:-1], foo[1:], strict=True)
|
||||
zip(foo[:-1], foo[1:], strict=False)
|
||||
zip(foo[:-1], foo[1:], strict=bool(foo))
|
||||
|
||||
@@ -2,12 +2,24 @@
|
||||
# noqa # comment
|
||||
print() # noqa
|
||||
print() # noqa # comment
|
||||
print() # noqa # comment
|
||||
print() # noqa comment
|
||||
print() # noqa comment
|
||||
print(a) # noqa
|
||||
print(a) # noqa # comment
|
||||
print(a) # noqa # comment
|
||||
print(a) # noqa comment
|
||||
print(a) # noqa comment
|
||||
|
||||
# noqa: E501, F821
|
||||
# noqa: E501, F821 # comment
|
||||
print() # noqa: E501, F821
|
||||
print() # noqa: E501, F821 # comment
|
||||
print() # noqa: E501, F821 # comment
|
||||
print() # noqa: E501, F821 comment
|
||||
print() # noqa: E501, F821 comment
|
||||
print(a) # noqa: E501, F821
|
||||
print(a) # noqa: E501, F821 # comment
|
||||
print(a) # noqa: E501, F821 # comment
|
||||
print(a) # noqa: E501, F821 comment
|
||||
print(a) # noqa: E501, F821 comment
|
||||
|
||||
@@ -45,3 +45,10 @@ def still_good():
|
||||
return process()
|
||||
except MyException:
|
||||
logger.exception("process failed")
|
||||
|
||||
def good_noexcept():
|
||||
try:
|
||||
pass
|
||||
return process()
|
||||
finally:
|
||||
logger.exception("process failed")
|
||||
|
||||
@@ -9,30 +9,30 @@ Running from the repo root should pick up and enforce the appropriate settings f
|
||||
|
||||
```console
|
||||
∴ cargo run -p ruff_cli -- check crates/ruff/resources/test/project/
|
||||
crates/ruff/resources/test/project/examples/.dotfiles/script.py:1:1: I001 Import block is un-sorted or un-formatted
|
||||
crates/ruff/resources/test/project/examples/.dotfiles/script.py:1:8: F401 `numpy` imported but unused
|
||||
crates/ruff/resources/test/project/examples/.dotfiles/script.py:2:17: F401 `app.app_file` imported but unused
|
||||
crates/ruff/resources/test/project/examples/docs/docs/file.py:1:1: I001 Import block is un-sorted or un-formatted
|
||||
crates/ruff/resources/test/project/examples/docs/docs/file.py:8:5: F841 Local variable `x` is assigned to but never used
|
||||
crates/ruff/resources/test/project/project/file.py:1:8: F401 `os` imported but unused
|
||||
crates/ruff/resources/test/project/project/import_file.py:1:1: I001 Import block is un-sorted or un-formatted
|
||||
crates/ruff/resources/test/project/examples/.dotfiles/script.py:1:1: I001 [*] Import block is un-sorted or un-formatted
|
||||
crates/ruff/resources/test/project/examples/.dotfiles/script.py:1:8: F401 [*] `numpy` imported but unused
|
||||
crates/ruff/resources/test/project/examples/.dotfiles/script.py:2:17: F401 [*] `app.app_file` imported but unused
|
||||
crates/ruff/resources/test/project/examples/docs/docs/file.py:1:1: I001 [*] Import block is un-sorted or un-formatted
|
||||
crates/ruff/resources/test/project/examples/docs/docs/file.py:8:5: F841 [*] Local variable `x` is assigned to but never used
|
||||
crates/ruff/resources/test/project/project/file.py:1:8: F401 [*] `os` imported but unused
|
||||
crates/ruff/resources/test/project/project/import_file.py:1:1: I001 [*] Import block is un-sorted or un-formatted
|
||||
Found 7 errors.
|
||||
7 potentially fixable with the --fix option.
|
||||
[*] 7 potentially fixable with the --fix option.
|
||||
```
|
||||
|
||||
Running from the project directory itself should exhibit the same behavior:
|
||||
|
||||
```console
|
||||
∴ (cd crates/ruff/resources/test/project/ && cargo run -p ruff_cli -- check .)
|
||||
examples/.dotfiles/script.py:1:1: I001 Import block is un-sorted or un-formatted
|
||||
examples/.dotfiles/script.py:1:8: F401 `numpy` imported but unused
|
||||
examples/.dotfiles/script.py:2:17: F401 `app.app_file` imported but unused
|
||||
examples/docs/docs/file.py:1:1: I001 Import block is un-sorted or un-formatted
|
||||
examples/docs/docs/file.py:8:5: F841 Local variable `x` is assigned to but never used
|
||||
project/file.py:1:8: F401 `os` imported but unused
|
||||
project/import_file.py:1:1: I001 Import block is un-sorted or un-formatted
|
||||
examples/.dotfiles/script.py:1:1: I001 [*] Import block is un-sorted or un-formatted
|
||||
examples/.dotfiles/script.py:1:8: F401 [*] `numpy` imported but unused
|
||||
examples/.dotfiles/script.py:2:17: F401 [*] `app.app_file` imported but unused
|
||||
examples/docs/docs/file.py:1:1: I001 [*] Import block is un-sorted or un-formatted
|
||||
examples/docs/docs/file.py:8:5: F841 [*] Local variable `x` is assigned to but never used
|
||||
project/file.py:1:8: F401 [*] `os` imported but unused
|
||||
project/import_file.py:1:1: I001 [*] Import block is un-sorted or un-formatted
|
||||
Found 7 errors.
|
||||
7 potentially fixable with the --fix option.
|
||||
[*] 7 potentially fixable with the --fix option.
|
||||
```
|
||||
|
||||
Running from the sub-package directory should exhibit the same behavior, but omit the top-level
|
||||
@@ -40,10 +40,10 @@ files:
|
||||
|
||||
```console
|
||||
∴ (cd crates/ruff/resources/test/project/examples/docs && cargo run -p ruff_cli -- check .)
|
||||
docs/file.py:1:1: I001 Import block is un-sorted or un-formatted
|
||||
docs/file.py:8:5: F841 Local variable `x` is assigned to but never used
|
||||
docs/file.py:1:1: I001 [*] Import block is un-sorted or un-formatted
|
||||
docs/file.py:8:5: F841 [*] Local variable `x` is assigned to but never used
|
||||
Found 2 errors.
|
||||
2 potentially fixable with the --fix option.
|
||||
[*] 2 potentially fixable with the --fix option.
|
||||
```
|
||||
|
||||
`--config` should force Ruff to use the specified `pyproject.toml` for all files, and resolve
|
||||
@@ -51,17 +51,17 @@ file paths from the current working directory:
|
||||
|
||||
```console
|
||||
∴ (cargo run -p ruff_cli -- check --config=crates/ruff/resources/test/project/pyproject.toml crates/ruff/resources/test/project/)
|
||||
crates/ruff/resources/test/project/examples/.dotfiles/script.py:1:8: F401 `numpy` imported but unused
|
||||
crates/ruff/resources/test/project/examples/.dotfiles/script.py:2:17: F401 `app.app_file` imported but unused
|
||||
crates/ruff/resources/test/project/examples/docs/docs/concepts/file.py:1:8: F401 `os` imported but unused
|
||||
crates/ruff/resources/test/project/examples/docs/docs/file.py:1:1: I001 Import block is un-sorted or un-formatted
|
||||
crates/ruff/resources/test/project/examples/docs/docs/file.py:1:8: F401 `os` imported but unused
|
||||
crates/ruff/resources/test/project/examples/docs/docs/file.py:3:8: F401 `numpy` imported but unused
|
||||
crates/ruff/resources/test/project/examples/docs/docs/file.py:4:27: F401 `docs.concepts.file` imported but unused
|
||||
crates/ruff/resources/test/project/examples/excluded/script.py:1:8: F401 `os` imported but unused
|
||||
crates/ruff/resources/test/project/project/file.py:1:8: F401 `os` imported but unused
|
||||
crates/ruff/resources/test/project/examples/.dotfiles/script.py:1:8: F401 [*] `numpy` imported but unused
|
||||
crates/ruff/resources/test/project/examples/.dotfiles/script.py:2:17: F401 [*] `app.app_file` imported but unused
|
||||
crates/ruff/resources/test/project/examples/docs/docs/concepts/file.py:1:8: F401 [*] `os` imported but unused
|
||||
crates/ruff/resources/test/project/examples/docs/docs/file.py:1:1: I001 [*] Import block is un-sorted or un-formatted
|
||||
crates/ruff/resources/test/project/examples/docs/docs/file.py:1:8: F401 [*] `os` imported but unused
|
||||
crates/ruff/resources/test/project/examples/docs/docs/file.py:3:8: F401 [*] `numpy` imported but unused
|
||||
crates/ruff/resources/test/project/examples/docs/docs/file.py:4:27: F401 [*] `docs.concepts.file` imported but unused
|
||||
crates/ruff/resources/test/project/examples/excluded/script.py:1:8: F401 [*] `os` imported but unused
|
||||
crates/ruff/resources/test/project/project/file.py:1:8: F401 [*] `os` imported but unused
|
||||
Found 9 errors.
|
||||
9 potentially fixable with the --fix option.
|
||||
[*] 9 potentially fixable with the --fix option.
|
||||
```
|
||||
|
||||
Running from a parent directory should "ignore" the `exclude` (hence, `concepts/file.py` gets
|
||||
@@ -69,21 +69,21 @@ included in the output):
|
||||
|
||||
```console
|
||||
∴ (cd crates/ruff/resources/test/project/examples && cargo run -p ruff_cli -- check --config=docs/ruff.toml .)
|
||||
docs/docs/concepts/file.py:5:5: F841 Local variable `x` is assigned to but never used
|
||||
docs/docs/file.py:1:1: I001 Import block is un-sorted or un-formatted
|
||||
docs/docs/file.py:8:5: F841 Local variable `x` is assigned to but never used
|
||||
excluded/script.py:5:5: F841 Local variable `x` is assigned to but never used
|
||||
docs/docs/concepts/file.py:5:5: F841 [*] Local variable `x` is assigned to but never used
|
||||
docs/docs/file.py:1:1: I001 [*] Import block is un-sorted or un-formatted
|
||||
docs/docs/file.py:8:5: F841 [*] Local variable `x` is assigned to but never used
|
||||
excluded/script.py:5:5: F841 [*] Local variable `x` is assigned to but never used
|
||||
Found 4 errors.
|
||||
4 potentially fixable with the --fix option.
|
||||
[*] 4 potentially fixable with the --fix option.
|
||||
```
|
||||
|
||||
Passing an excluded directory directly should report errors in the contained files:
|
||||
|
||||
```console
|
||||
∴ cargo run -p ruff_cli -- check crates/ruff/resources/test/project/examples/excluded/
|
||||
crates/ruff/resources/test/project/examples/excluded/script.py:1:8: F401 `os` imported but unused
|
||||
crates/ruff/resources/test/project/examples/excluded/script.py:1:8: F401 [*] `os` imported but unused
|
||||
Found 1 error.
|
||||
1 potentially fixable with the --fix option.
|
||||
[*] 1 potentially fixable with the --fix option.
|
||||
```
|
||||
|
||||
Unless we `--force-exclude`:
|
||||
|
||||
@@ -28,7 +28,7 @@ fn apply_fixes<'a>(
|
||||
locator: &'a Locator<'a>,
|
||||
) -> (String, FixTable) {
|
||||
let mut output = String::with_capacity(locator.len());
|
||||
let mut last_pos: Location = Location::new(1, 0);
|
||||
let mut last_pos: Option<Location> = None;
|
||||
let mut applied: BTreeSet<&Fix> = BTreeSet::default();
|
||||
let mut fixed = FxHashMap::default();
|
||||
|
||||
@@ -50,25 +50,25 @@ fn apply_fixes<'a>(
|
||||
|
||||
// Best-effort approach: if this fix overlaps with a fix we've already applied,
|
||||
// skip it.
|
||||
if last_pos > fix.location {
|
||||
if last_pos.map_or(false, |last_pos| last_pos >= fix.location) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Add all contents from `last_pos` to `fix.location`.
|
||||
let slice = locator.slice(Range::new(last_pos, fix.location));
|
||||
let slice = locator.slice(Range::new(last_pos.unwrap_or_default(), fix.location));
|
||||
output.push_str(slice);
|
||||
|
||||
// Add the patch itself.
|
||||
output.push_str(&fix.content);
|
||||
|
||||
// Track that the fix was applied.
|
||||
last_pos = fix.end_location;
|
||||
last_pos = Some(fix.end_location);
|
||||
applied.insert(fix);
|
||||
*fixed.entry(rule).or_default() += 1;
|
||||
}
|
||||
|
||||
// Add the remaining content.
|
||||
let slice = locator.skip(last_pos);
|
||||
let slice = locator.skip(last_pos.unwrap_or_default());
|
||||
output.push_str(slice);
|
||||
|
||||
(output, fixed)
|
||||
@@ -113,14 +113,14 @@ mod tests {
|
||||
use ruff_python_ast::source_code::Locator;
|
||||
|
||||
use crate::autofix::{apply_fix, apply_fixes};
|
||||
use crate::rules::pycodestyle::rules::NoNewLineAtEndOfFile;
|
||||
use crate::rules::pycodestyle::rules::MissingNewlineAtEndOfFile;
|
||||
|
||||
fn create_diagnostics(fixes: impl IntoIterator<Item = Fix>) -> Vec<Diagnostic> {
|
||||
fixes
|
||||
.into_iter()
|
||||
.map(|fix| Diagnostic {
|
||||
// The choice of rule here is arbitrary.
|
||||
kind: NoNewLineAtEndOfFile.into(),
|
||||
kind: MissingNewlineAtEndOfFile.into(),
|
||||
location: fix.location,
|
||||
end_location: fix.end_location,
|
||||
fix: Some(fix),
|
||||
@@ -194,7 +194,7 @@ class A:
|
||||
fn apply_two_removals() {
|
||||
let locator = Locator::new(
|
||||
r#"
|
||||
class A(object, object):
|
||||
class A(object, object, object):
|
||||
...
|
||||
"#
|
||||
.trim(),
|
||||
@@ -202,13 +202,13 @@ class A(object, object):
|
||||
let diagnostics = create_diagnostics([
|
||||
Fix {
|
||||
content: String::new(),
|
||||
location: Location::new(1, 7),
|
||||
location: Location::new(1, 8),
|
||||
end_location: Location::new(1, 16),
|
||||
},
|
||||
Fix {
|
||||
content: String::new(),
|
||||
location: Location::new(1, 16),
|
||||
end_location: Location::new(1, 23),
|
||||
location: Location::new(1, 22),
|
||||
end_location: Location::new(1, 30),
|
||||
},
|
||||
]);
|
||||
let (contents, fixed) = apply_fixes(diagnostics.iter(), &locator);
|
||||
@@ -216,7 +216,7 @@ class A(object, object):
|
||||
assert_eq!(
|
||||
contents,
|
||||
r#"
|
||||
class A:
|
||||
class A(object):
|
||||
...
|
||||
"#
|
||||
.trim()
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -165,13 +165,15 @@ pub fn check_logical_lines(
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
let should_fix = autofix.into() && settings.rules.should_fix(Rule::MissingWhitespace);
|
||||
|
||||
#[cfg(not(feature = "logical_lines"))]
|
||||
#[cfg(not(debug_assertions))]
|
||||
let should_fix = false;
|
||||
|
||||
for diagnostic in missing_whitespace(&line.text, start_loc.row(), should_fix) {
|
||||
for diagnostic in
|
||||
missing_whitespace(&line.text, start_loc.row(), should_fix, indent_level)
|
||||
{
|
||||
if settings.rules.enabled(diagnostic.kind.rule()) {
|
||||
diagnostics.push(diagnostic);
|
||||
}
|
||||
@@ -179,11 +181,11 @@ pub fn check_logical_lines(
|
||||
}
|
||||
|
||||
if line.flags.contains(TokenFlags::BRACKET) {
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
let should_fix =
|
||||
autofix.into() && settings.rules.should_fix(Rule::WhitespaceBeforeParameters);
|
||||
|
||||
#[cfg(not(feature = "logical_lines"))]
|
||||
#[cfg(not(debug_assertions))]
|
||||
let should_fix = false;
|
||||
|
||||
for diagnostic in whitespace_before_parameters(&line.tokens, should_fix) {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
//! `NoQA` enforcement and validation.
|
||||
|
||||
use log::warn;
|
||||
use nohash_hasher::IntMap;
|
||||
use rustpython_parser::ast::Location;
|
||||
|
||||
@@ -10,7 +9,7 @@ use ruff_python_ast::types::Range;
|
||||
|
||||
use crate::codes::NoqaCode;
|
||||
use crate::noqa;
|
||||
use crate::noqa::{extract_file_exemption, Directive, Exemption};
|
||||
use crate::noqa::{Directive, FileExemption};
|
||||
use crate::registry::{AsRule, Rule};
|
||||
use crate::rule_redirects::get_redirect_target;
|
||||
use crate::rules::ruff::rules::{UnusedCodes, UnusedNOQA};
|
||||
@@ -26,63 +25,47 @@ pub fn check_noqa(
|
||||
) -> Vec<usize> {
|
||||
let enforce_noqa = settings.rules.enabled(Rule::UnusedNOQA);
|
||||
|
||||
// Whether the file is exempted from all checks.
|
||||
let mut file_exempted = false;
|
||||
let lines: Vec<&str> = contents.universal_newlines().collect();
|
||||
|
||||
// Codes that are globally exempted (within the current file).
|
||||
let mut file_exemptions: Vec<NoqaCode> = vec![];
|
||||
// Identify any codes that are globally exempted (within the current file).
|
||||
let exemption = noqa::file_exemption(&lines, commented_lines);
|
||||
|
||||
// Map from line number to `noqa` directive on that line, along with any codes
|
||||
// that were matched by the directive.
|
||||
let mut noqa_directives: IntMap<usize, (Directive, Vec<NoqaCode>)> = IntMap::default();
|
||||
|
||||
// Indices of diagnostics that were ignored by a `noqa` directive.
|
||||
let mut ignored_diagnostics = vec![];
|
||||
|
||||
let lines: Vec<&str> = contents.universal_newlines().collect();
|
||||
for lineno in commented_lines {
|
||||
match extract_file_exemption(lines[lineno - 1]) {
|
||||
Exemption::All => {
|
||||
file_exempted = true;
|
||||
}
|
||||
Exemption::Codes(codes) => {
|
||||
file_exemptions.extend(codes.into_iter().filter_map(|code| {
|
||||
if let Ok(rule) = Rule::from_code(get_redirect_target(code).unwrap_or(code)) {
|
||||
Some(rule.noqa_code())
|
||||
} else {
|
||||
warn!("Invalid code provided to `# ruff: noqa`: {}", code);
|
||||
None
|
||||
}
|
||||
}));
|
||||
}
|
||||
Exemption::None => {}
|
||||
}
|
||||
|
||||
if enforce_noqa {
|
||||
// Extract all `noqa` directives.
|
||||
if enforce_noqa {
|
||||
for lineno in commented_lines {
|
||||
noqa_directives
|
||||
.entry(lineno - 1)
|
||||
.or_insert_with(|| (noqa::extract_noqa_directive(lines[lineno - 1]), vec![]));
|
||||
}
|
||||
}
|
||||
|
||||
// Indices of diagnostics that were ignored by a `noqa` directive.
|
||||
let mut ignored_diagnostics = vec![];
|
||||
|
||||
// Remove any ignored diagnostics.
|
||||
for (index, diagnostic) in diagnostics.iter().enumerate() {
|
||||
if matches!(diagnostic.kind.rule(), Rule::BlanketNOQA) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// If the file is exempted, ignore all diagnostics.
|
||||
if file_exempted {
|
||||
ignored_diagnostics.push(index);
|
||||
continue;
|
||||
}
|
||||
|
||||
// If the diagnostic is ignored by a global exemption, ignore it.
|
||||
if !file_exemptions.is_empty() {
|
||||
if file_exemptions.contains(&diagnostic.kind.rule().noqa_code()) {
|
||||
match &exemption {
|
||||
FileExemption::All => {
|
||||
// If the file is exempted, ignore all diagnostics.
|
||||
ignored_diagnostics.push(index);
|
||||
continue;
|
||||
}
|
||||
FileExemption::Codes(codes) => {
|
||||
// If the diagnostic is ignored by a global exemption, ignore it.
|
||||
if codes.contains(&diagnostic.kind.rule().noqa_code()) {
|
||||
ignored_diagnostics.push(index);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
FileExemption::None => {}
|
||||
}
|
||||
|
||||
// Is the violation ignored by a `noqa` directive on the parent line?
|
||||
@@ -143,30 +126,26 @@ pub fn check_noqa(
|
||||
match directive {
|
||||
Directive::All(leading_spaces, start_byte, end_byte, trailing_spaces) => {
|
||||
if matches.is_empty() {
|
||||
let start = lines[row][..start_byte].chars().count();
|
||||
let end = start + lines[row][start_byte..end_byte].chars().count();
|
||||
let start_char = lines[row][..start_byte].chars().count();
|
||||
let end_char =
|
||||
start_char + lines[row][start_byte..end_byte].chars().count();
|
||||
|
||||
let mut diagnostic = Diagnostic::new(
|
||||
UnusedNOQA { codes: None },
|
||||
Range::new(Location::new(row + 1, start), Location::new(row + 1, end)),
|
||||
Range::new(
|
||||
Location::new(row + 1, start_char),
|
||||
Location::new(row + 1, end_char),
|
||||
),
|
||||
);
|
||||
if autofix.into() && settings.rules.should_fix(diagnostic.kind.rule()) {
|
||||
if start - leading_spaces == 0 && end == lines[row].chars().count() {
|
||||
diagnostic.amend(Fix::deletion(
|
||||
Location::new(row + 1, 0),
|
||||
Location::new(row + 2, 0),
|
||||
));
|
||||
} else if end == lines[row].chars().count() {
|
||||
diagnostic.amend(Fix::deletion(
|
||||
Location::new(row + 1, start - leading_spaces),
|
||||
Location::new(row + 1, end + trailing_spaces),
|
||||
));
|
||||
} else {
|
||||
diagnostic.amend(Fix::deletion(
|
||||
Location::new(row + 1, start),
|
||||
Location::new(row + 1, end + trailing_spaces),
|
||||
));
|
||||
}
|
||||
diagnostic.amend(delete_noqa(
|
||||
row,
|
||||
lines[row],
|
||||
leading_spaces,
|
||||
start_byte,
|
||||
end_byte,
|
||||
trailing_spaces,
|
||||
));
|
||||
}
|
||||
diagnostics.push(diagnostic);
|
||||
}
|
||||
@@ -207,8 +186,9 @@ pub fn check_noqa(
|
||||
&& unknown_codes.is_empty()
|
||||
&& unmatched_codes.is_empty())
|
||||
{
|
||||
let start = lines[row][..start_byte].chars().count();
|
||||
let end = start + lines[row][start_byte..end_byte].chars().count();
|
||||
let start_char = lines[row][..start_byte].chars().count();
|
||||
let end_char =
|
||||
start_char + lines[row][start_byte..end_byte].chars().count();
|
||||
|
||||
let mut diagnostic = Diagnostic::new(
|
||||
UnusedNOQA {
|
||||
@@ -227,32 +207,26 @@ pub fn check_noqa(
|
||||
.collect(),
|
||||
}),
|
||||
},
|
||||
Range::new(Location::new(row + 1, start), Location::new(row + 1, end)),
|
||||
Range::new(
|
||||
Location::new(row + 1, start_char),
|
||||
Location::new(row + 1, end_char),
|
||||
),
|
||||
);
|
||||
if autofix.into() && settings.rules.should_fix(diagnostic.kind.rule()) {
|
||||
if valid_codes.is_empty() {
|
||||
if start - leading_spaces == 0 && end == lines[row].chars().count()
|
||||
{
|
||||
diagnostic.amend(Fix::deletion(
|
||||
Location::new(row + 1, 0),
|
||||
Location::new(row + 2, 0),
|
||||
));
|
||||
} else if end == lines[row].chars().count() {
|
||||
diagnostic.amend(Fix::deletion(
|
||||
Location::new(row + 1, start - leading_spaces),
|
||||
Location::new(row + 1, end + trailing_spaces),
|
||||
));
|
||||
} else {
|
||||
diagnostic.amend(Fix::deletion(
|
||||
Location::new(row + 1, start),
|
||||
Location::new(row + 1, end + trailing_spaces),
|
||||
));
|
||||
}
|
||||
diagnostic.amend(delete_noqa(
|
||||
row,
|
||||
lines[row],
|
||||
leading_spaces,
|
||||
start_byte,
|
||||
end_byte,
|
||||
trailing_spaces,
|
||||
));
|
||||
} else {
|
||||
diagnostic.amend(Fix::replacement(
|
||||
format!("# noqa: {}", valid_codes.join(", ")),
|
||||
Location::new(row + 1, start),
|
||||
Location::new(row + 1, end),
|
||||
Location::new(row + 1, start_char),
|
||||
Location::new(row + 1, end_char),
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -267,3 +241,42 @@ pub fn check_noqa(
|
||||
ignored_diagnostics.sort_unstable();
|
||||
ignored_diagnostics
|
||||
}
|
||||
|
||||
/// Generate a [`Fix`] to delete a `noqa` directive.
|
||||
fn delete_noqa(
|
||||
row: usize,
|
||||
line: &str,
|
||||
leading_spaces: usize,
|
||||
start_byte: usize,
|
||||
end_byte: usize,
|
||||
trailing_spaces: usize,
|
||||
) -> Fix {
|
||||
if start_byte - leading_spaces == 0 && end_byte == line.len() {
|
||||
// Ex) `# noqa`
|
||||
Fix::deletion(Location::new(row + 1, 0), Location::new(row + 2, 0))
|
||||
} else if end_byte == line.len() {
|
||||
// Ex) `x = 1 # noqa`
|
||||
let start_char = line[..start_byte].chars().count();
|
||||
let end_char = start_char + line[start_byte..end_byte].chars().count();
|
||||
Fix::deletion(
|
||||
Location::new(row + 1, start_char - leading_spaces),
|
||||
Location::new(row + 1, end_char + trailing_spaces),
|
||||
)
|
||||
} else if line[end_byte..].trim_start().starts_with('#') {
|
||||
// Ex) `x = 1 # noqa # type: ignore`
|
||||
let start_char = line[..start_byte].chars().count();
|
||||
let end_char = start_char + line[start_byte..end_byte].chars().count();
|
||||
Fix::deletion(
|
||||
Location::new(row + 1, start_char),
|
||||
Location::new(row + 1, end_char + trailing_spaces),
|
||||
)
|
||||
} else {
|
||||
// Ex) `x = 1 # noqa here`
|
||||
let start_char = line[..start_byte].chars().count();
|
||||
let end_char = start_char + line[start_byte..end_byte].chars().count();
|
||||
Fix::deletion(
|
||||
Location::new(row + 1, start_char + 1 + 1),
|
||||
Location::new(row + 1, end_char + trailing_spaces),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,8 +12,8 @@ use crate::rules::flake8_executable::rules::{
|
||||
shebang_missing, shebang_newline, shebang_not_executable, shebang_python, shebang_whitespace,
|
||||
};
|
||||
use crate::rules::pycodestyle::rules::{
|
||||
doc_line_too_long, indentation_contains_tabs, line_too_long, mixed_spaces_and_tabs,
|
||||
no_newline_at_end_of_file, trailing_whitespace,
|
||||
doc_line_too_long, line_too_long, mixed_spaces_and_tabs, no_newline_at_end_of_file,
|
||||
tab_indentation, trailing_whitespace,
|
||||
};
|
||||
use crate::rules::pygrep_hooks::rules::{blanket_noqa, blanket_type_ignore};
|
||||
use crate::rules::pylint;
|
||||
@@ -35,25 +35,25 @@ pub fn check_physical_lines(
|
||||
let enforce_blanket_noqa = settings.rules.enabled(Rule::BlanketNOQA);
|
||||
let enforce_shebang_not_executable = settings.rules.enabled(Rule::ShebangNotExecutable);
|
||||
let enforce_shebang_missing = settings.rules.enabled(Rule::ShebangMissingExecutableFile);
|
||||
let enforce_shebang_whitespace = settings.rules.enabled(Rule::ShebangWhitespace);
|
||||
let enforce_shebang_newline = settings.rules.enabled(Rule::ShebangNewline);
|
||||
let enforce_shebang_python = settings.rules.enabled(Rule::ShebangPython);
|
||||
let enforce_shebang_whitespace = settings.rules.enabled(Rule::ShebangLeadingWhitespace);
|
||||
let enforce_shebang_newline = settings.rules.enabled(Rule::ShebangNotFirstLine);
|
||||
let enforce_shebang_python = settings.rules.enabled(Rule::ShebangMissingPython);
|
||||
let enforce_blanket_type_ignore = settings.rules.enabled(Rule::BlanketTypeIgnore);
|
||||
let enforce_doc_line_too_long = settings.rules.enabled(Rule::DocLineTooLong);
|
||||
let enforce_line_too_long = settings.rules.enabled(Rule::LineTooLong);
|
||||
let enforce_no_newline_at_end_of_file = settings.rules.enabled(Rule::NoNewLineAtEndOfFile);
|
||||
let enforce_no_newline_at_end_of_file = settings.rules.enabled(Rule::MissingNewlineAtEndOfFile);
|
||||
let enforce_unnecessary_coding_comment = settings.rules.enabled(Rule::UTF8EncodingDeclaration);
|
||||
let enforce_mixed_spaces_and_tabs = settings.rules.enabled(Rule::MixedSpacesAndTabs);
|
||||
let enforce_bidirectional_unicode = settings.rules.enabled(Rule::BidirectionalUnicode);
|
||||
let enforce_trailing_whitespace = settings.rules.enabled(Rule::TrailingWhitespace);
|
||||
let enforce_blank_line_contains_whitespace =
|
||||
settings.rules.enabled(Rule::BlankLineContainsWhitespace);
|
||||
let enforce_indentation_contains_tabs = settings.rules.enabled(Rule::IndentationContainsTabs);
|
||||
settings.rules.enabled(Rule::BlankLineWithWhitespace);
|
||||
let enforce_tab_indentation = settings.rules.enabled(Rule::TabIndentation);
|
||||
|
||||
let fix_unnecessary_coding_comment =
|
||||
autofix.into() && settings.rules.should_fix(Rule::UTF8EncodingDeclaration);
|
||||
let fix_shebang_whitespace =
|
||||
autofix.into() && settings.rules.should_fix(Rule::ShebangWhitespace);
|
||||
autofix.into() && settings.rules.should_fix(Rule::ShebangLeadingWhitespace);
|
||||
|
||||
let mut commented_lines_iter = commented_lines.iter().peekable();
|
||||
let mut doc_lines_iter = doc_lines.iter().peekable();
|
||||
@@ -154,8 +154,8 @@ pub fn check_physical_lines(
|
||||
}
|
||||
}
|
||||
|
||||
if enforce_indentation_contains_tabs {
|
||||
if let Some(diagnostic) = indentation_contains_tabs(index, line) {
|
||||
if enforce_tab_indentation {
|
||||
if let Some(diagnostic) = tab_indentation(index, line) {
|
||||
diagnostics.push(diagnostic);
|
||||
}
|
||||
}
|
||||
@@ -165,7 +165,7 @@ pub fn check_physical_lines(
|
||||
if let Some(diagnostic) = no_newline_at_end_of_file(
|
||||
locator,
|
||||
stylist,
|
||||
autofix.into() && settings.rules.should_fix(Rule::NoNewLineAtEndOfFile),
|
||||
autofix.into() && settings.rules.should_fix(Rule::MissingNewlineAtEndOfFile),
|
||||
) {
|
||||
diagnostics.push(diagnostic);
|
||||
}
|
||||
|
||||
@@ -54,9 +54,9 @@ pub fn check_tokens(
|
||||
]);
|
||||
|
||||
let enforce_trailing_comma = settings.rules.any_enabled(&[
|
||||
Rule::TrailingCommaMissing,
|
||||
Rule::TrailingCommaOnBareTupleProhibited,
|
||||
Rule::TrailingCommaProhibited,
|
||||
Rule::MissingTrailingComma,
|
||||
Rule::TrailingCommaOnBareTuple,
|
||||
Rule::ProhibitedTrailingComma,
|
||||
]);
|
||||
let enforce_extraneous_parenthesis = settings.rules.enabled(Rule::ExtraneousParentheses);
|
||||
let enforce_type_comment_in_stub = settings.rules.enabled(Rule::TypeCommentInStub);
|
||||
|
||||
@@ -26,67 +26,67 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<Rule> {
|
||||
Some(match (linter, code) {
|
||||
// pycodestyle errors
|
||||
(Pycodestyle, "E101") => Rule::MixedSpacesAndTabs,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
(Pycodestyle, "E111") => Rule::IndentationWithInvalidMultiple,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
(Pycodestyle, "E112") => Rule::NoIndentedBlock,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
(Pycodestyle, "E113") => Rule::UnexpectedIndentation,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
(Pycodestyle, "E114") => Rule::IndentationWithInvalidMultipleComment,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
(Pycodestyle, "E115") => Rule::NoIndentedBlockComment,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
(Pycodestyle, "E116") => Rule::UnexpectedIndentationComment,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
(Pycodestyle, "E117") => Rule::OverIndented,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
(Pycodestyle, "E201") => Rule::WhitespaceAfterOpenBracket,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
(Pycodestyle, "E202") => Rule::WhitespaceBeforeCloseBracket,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
(Pycodestyle, "E203") => Rule::WhitespaceBeforePunctuation,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
(Pycodestyle, "E211") => Rule::WhitespaceBeforeParameters,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
(Pycodestyle, "E221") => Rule::MultipleSpacesBeforeOperator,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
(Pycodestyle, "E222") => Rule::MultipleSpacesAfterOperator,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
(Pycodestyle, "E223") => Rule::TabBeforeOperator,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
(Pycodestyle, "E224") => Rule::TabAfterOperator,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
(Pycodestyle, "E225") => Rule::MissingWhitespaceAroundOperator,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
(Pycodestyle, "E226") => Rule::MissingWhitespaceAroundArithmeticOperator,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
(Pycodestyle, "E227") => Rule::MissingWhitespaceAroundBitwiseOrShiftOperator,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
(Pycodestyle, "E228") => Rule::MissingWhitespaceAroundModuloOperator,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
(Pycodestyle, "E231") => Rule::MissingWhitespace,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
(Pycodestyle, "E251") => Rule::UnexpectedSpacesAroundKeywordParameterEquals,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
(Pycodestyle, "E252") => Rule::MissingWhitespaceAroundParameterEquals,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
(Pycodestyle, "E261") => Rule::TooFewSpacesBeforeInlineComment,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
(Pycodestyle, "E262") => Rule::NoSpaceAfterInlineComment,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
(Pycodestyle, "E265") => Rule::NoSpaceAfterBlockComment,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
(Pycodestyle, "E266") => Rule::MultipleLeadingHashesForBlockComment,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
(Pycodestyle, "E271") => Rule::MultipleSpacesAfterKeyword,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
(Pycodestyle, "E272") => Rule::MultipleSpacesBeforeKeyword,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
(Pycodestyle, "E273") => Rule::TabAfterKeyword,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
(Pycodestyle, "E274") => Rule::TabBeforeKeyword,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
(Pycodestyle, "E275") => Rule::MissingWhitespaceAfterKeyword,
|
||||
(Pycodestyle, "E401") => Rule::MultipleImportsOnOneLine,
|
||||
(Pycodestyle, "E402") => Rule::ModuleImportNotAtTopOfFile,
|
||||
@@ -108,20 +108,20 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<Rule> {
|
||||
(Pycodestyle, "E999") => Rule::SyntaxError,
|
||||
|
||||
// pycodestyle warnings
|
||||
(Pycodestyle, "W191") => Rule::IndentationContainsTabs,
|
||||
(Pycodestyle, "W191") => Rule::TabIndentation,
|
||||
(Pycodestyle, "W291") => Rule::TrailingWhitespace,
|
||||
(Pycodestyle, "W292") => Rule::NoNewLineAtEndOfFile,
|
||||
(Pycodestyle, "W293") => Rule::BlankLineContainsWhitespace,
|
||||
(Pycodestyle, "W292") => Rule::MissingNewlineAtEndOfFile,
|
||||
(Pycodestyle, "W293") => Rule::BlankLineWithWhitespace,
|
||||
(Pycodestyle, "W505") => Rule::DocLineTooLong,
|
||||
(Pycodestyle, "W605") => Rule::InvalidEscapeSequence,
|
||||
|
||||
// pyflakes
|
||||
(Pyflakes, "401") => Rule::UnusedImport,
|
||||
(Pyflakes, "402") => Rule::ImportShadowedByLoopVar,
|
||||
(Pyflakes, "403") => Rule::ImportStar,
|
||||
(Pyflakes, "403") => Rule::UndefinedLocalWithImportStar,
|
||||
(Pyflakes, "404") => Rule::LateFutureImport,
|
||||
(Pyflakes, "405") => Rule::ImportStarUsage,
|
||||
(Pyflakes, "406") => Rule::ImportStarNotPermitted,
|
||||
(Pyflakes, "405") => Rule::UndefinedLocalWithImportStarUsage,
|
||||
(Pyflakes, "406") => Rule::UndefinedLocalWithNestedImportStarUsage,
|
||||
(Pyflakes, "407") => Rule::FutureFeatureNotDefined,
|
||||
(Pyflakes, "501") => Rule::PercentFormatInvalidFormat,
|
||||
(Pyflakes, "502") => Rule::PercentFormatExpectedMapping,
|
||||
@@ -141,7 +141,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<Rule> {
|
||||
(Pyflakes, "601") => Rule::MultiValueRepeatedKeyLiteral,
|
||||
(Pyflakes, "602") => Rule::MultiValueRepeatedKeyVariable,
|
||||
(Pyflakes, "621") => Rule::ExpressionsInStarAssignment,
|
||||
(Pyflakes, "622") => Rule::TwoStarredExpressions,
|
||||
(Pyflakes, "622") => Rule::MultipleStarredExpressions,
|
||||
(Pyflakes, "631") => Rule::AssertTuple,
|
||||
(Pyflakes, "632") => Rule::IsLiteral,
|
||||
(Pyflakes, "633") => Rule::InvalidPrintSyntax,
|
||||
@@ -168,36 +168,39 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<Rule> {
|
||||
(Pylint, "E0101") => Rule::ReturnInInit,
|
||||
(Pylint, "E0116") => Rule::ContinueInFinally,
|
||||
(Pylint, "E0117") => Rule::NonlocalWithoutBinding,
|
||||
(Pylint, "E0118") => Rule::UsedPriorGlobalDeclaration,
|
||||
(Pylint, "E0118") => Rule::LoadBeforeGlobalDeclaration,
|
||||
(Pylint, "E0604") => Rule::InvalidAllObject,
|
||||
(Pylint, "E0605") => Rule::InvalidAllFormat,
|
||||
(Pylint, "W1508") => Rule::InvalidEnvvarDefault,
|
||||
(Pylint, "E1142") => Rule::AwaitOutsideAsync,
|
||||
(Pylint, "E1205") => Rule::LoggingTooManyArgs,
|
||||
(Pylint, "E1206") => Rule::LoggingTooFewArgs,
|
||||
(Pylint, "E1307") => Rule::BadStringFormatType,
|
||||
(Pylint, "E1310") => Rule::BadStrStripCall,
|
||||
(Pylint, "E1507") => Rule::InvalidEnvvarValue,
|
||||
(Pylint, "E2502") => Rule::BidirectionalUnicode,
|
||||
(Pylint, "E2510") => Rule::InvalidCharacterBackspace,
|
||||
(Pylint, "E2512") => Rule::InvalidCharacterSub,
|
||||
(Pylint, "E2513") => Rule::InvalidCharacterEsc,
|
||||
(Pylint, "E2514") => Rule::InvalidCharacterNul,
|
||||
(Pylint, "E2515") => Rule::InvalidCharacterZeroWidthSpace,
|
||||
(Pylint, "E1310") => Rule::BadStrStripCall,
|
||||
(Pylint, "E1507") => Rule::InvalidEnvvarValue,
|
||||
(Pylint, "R0133") => Rule::ComparisonOfConstant,
|
||||
(Pylint, "R0206") => Rule::PropertyWithParameters,
|
||||
(Pylint, "R0402") => Rule::ConsiderUsingFromImport,
|
||||
(Pylint, "R0402") => Rule::ManualFromImport,
|
||||
(Pylint, "R0911") => Rule::TooManyReturnStatements,
|
||||
(Pylint, "R0912") => Rule::TooManyBranches,
|
||||
(Pylint, "R0913") => Rule::TooManyArguments,
|
||||
(Pylint, "R0915") => Rule::TooManyStatements,
|
||||
(Pylint, "R1701") => Rule::ConsiderMergingIsinstance,
|
||||
(Pylint, "R1722") => Rule::ConsiderUsingSysExit,
|
||||
(Pylint, "R1701") => Rule::RepeatedIsinstanceCalls,
|
||||
(Pylint, "R1711") => Rule::UselessReturn,
|
||||
(Pylint, "R1722") => Rule::SysExitAlias,
|
||||
(Pylint, "R2004") => Rule::MagicValueComparison,
|
||||
(Pylint, "R5501") => Rule::CollapsibleElseIf,
|
||||
(Pylint, "W0120") => Rule::UselessElseOnLoop,
|
||||
(Pylint, "W0129") => Rule::AssertOnStringLiteral,
|
||||
(Pylint, "W0602") => Rule::GlobalVariableNotAssigned,
|
||||
(Pylint, "W0603") => Rule::GlobalStatement,
|
||||
(Pylint, "W0711") => Rule::BinaryOpException,
|
||||
(Pylint, "W1508") => Rule::InvalidEnvvarDefault,
|
||||
(Pylint, "W2901") => Rule::RedefinedLoopName,
|
||||
|
||||
// flake8-builtins
|
||||
@@ -212,7 +215,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<Rule> {
|
||||
(Flake8Bugbear, "005") => Rule::StripWithMultiCharacters,
|
||||
(Flake8Bugbear, "006") => Rule::MutableArgumentDefault,
|
||||
(Flake8Bugbear, "007") => Rule::UnusedLoopControlVariable,
|
||||
(Flake8Bugbear, "008") => Rule::FunctionCallArgumentDefault,
|
||||
(Flake8Bugbear, "008") => Rule::FunctionCallInDefaultArgument,
|
||||
(Flake8Bugbear, "009") => Rule::GetAttrWithConstant,
|
||||
(Flake8Bugbear, "010") => Rule::SetAttrWithConstant,
|
||||
(Flake8Bugbear, "011") => Rule::AssertFalse,
|
||||
@@ -286,8 +289,8 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<Rule> {
|
||||
(Flake8ImplicitStrConcat, "003") => Rule::ExplicitStringConcatenation,
|
||||
|
||||
// flake8-print
|
||||
(Flake8Print, "1") => Rule::PrintFound,
|
||||
(Flake8Print, "3") => Rule::PPrintFound,
|
||||
(Flake8Print, "1") => Rule::Print,
|
||||
(Flake8Print, "3") => Rule::PPrint,
|
||||
|
||||
// flake8-quotes
|
||||
(Flake8Quotes, "000") => Rule::BadQuotesInlineString,
|
||||
@@ -301,7 +304,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<Rule> {
|
||||
(Flake8Annotations, "003") => Rule::MissingTypeKwargs,
|
||||
(Flake8Annotations, "101") => Rule::MissingTypeSelf,
|
||||
(Flake8Annotations, "102") => Rule::MissingTypeCls,
|
||||
(Flake8Annotations, "201") => Rule::MissingReturnTypePublicFunction,
|
||||
(Flake8Annotations, "201") => Rule::MissingReturnTypeUndocumentedPublicFunction,
|
||||
(Flake8Annotations, "202") => Rule::MissingReturnTypePrivateFunction,
|
||||
(Flake8Annotations, "204") => Rule::MissingReturnTypeSpecialMethod,
|
||||
(Flake8Annotations, "205") => Rule::MissingReturnTypeStaticMethod,
|
||||
@@ -309,33 +312,32 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<Rule> {
|
||||
(Flake8Annotations, "401") => Rule::AnyType,
|
||||
|
||||
// flake8-2020
|
||||
(Flake82020, "101") => Rule::SysVersionSlice3Referenced,
|
||||
(Flake82020, "102") => Rule::SysVersion2Referenced,
|
||||
(Flake82020, "101") => Rule::SysVersionSlice3,
|
||||
(Flake82020, "102") => Rule::SysVersion2,
|
||||
(Flake82020, "103") => Rule::SysVersionCmpStr3,
|
||||
(Flake82020, "201") => Rule::SysVersionInfo0Eq3Referenced,
|
||||
(Flake82020, "202") => Rule::SixPY3Referenced,
|
||||
(Flake82020, "201") => Rule::SysVersionInfo0Eq3,
|
||||
(Flake82020, "202") => Rule::SixPY3,
|
||||
(Flake82020, "203") => Rule::SysVersionInfo1CmpInt,
|
||||
(Flake82020, "204") => Rule::SysVersionInfoMinorCmpInt,
|
||||
(Flake82020, "301") => Rule::SysVersion0Referenced,
|
||||
(Flake82020, "301") => Rule::SysVersion0,
|
||||
(Flake82020, "302") => Rule::SysVersionCmpStr10,
|
||||
(Flake82020, "303") => Rule::SysVersionSlice1Referenced,
|
||||
(Flake82020, "303") => Rule::SysVersionSlice1,
|
||||
|
||||
// flake8-simplify
|
||||
(Flake8Simplify, "101") => Rule::DuplicateIsinstanceCall,
|
||||
(Flake8Simplify, "102") => Rule::CollapsibleIf,
|
||||
(Flake8Simplify, "103") => Rule::NeedlessBool,
|
||||
(Flake8Simplify, "105") => Rule::UseContextlibSuppress,
|
||||
(Flake8Simplify, "105") => Rule::SuppressibleException,
|
||||
(Flake8Simplify, "107") => Rule::ReturnInTryExceptFinally,
|
||||
(Flake8Simplify, "108") => Rule::UseTernaryOperator,
|
||||
(Flake8Simplify, "108") => Rule::IfElseBlockInsteadOfIfExp,
|
||||
(Flake8Simplify, "109") => Rule::CompareWithTuple,
|
||||
(Flake8Simplify, "110") => Rule::ReimplementedBuiltin,
|
||||
// (Flake8Simplify, "111") => Rule::ReimplementedBuiltin,
|
||||
(Flake8Simplify, "112") => Rule::UseCapitalEnvironmentVariables,
|
||||
(Flake8Simplify, "112") => Rule::UncapitalizedEnvironmentVariables,
|
||||
(Flake8Simplify, "114") => Rule::IfWithSameArms,
|
||||
(Flake8Simplify, "115") => Rule::OpenFileWithContextHandler,
|
||||
(Flake8Simplify, "116") => Rule::ManualDictLookup,
|
||||
(Flake8Simplify, "116") => Rule::IfElseBlockInsteadOfDictLookup,
|
||||
(Flake8Simplify, "117") => Rule::MultipleWithStatements,
|
||||
(Flake8Simplify, "118") => Rule::KeyInDict,
|
||||
(Flake8Simplify, "118") => Rule::InDictKeys,
|
||||
(Flake8Simplify, "201") => Rule::NegateEqualOp,
|
||||
(Flake8Simplify, "202") => Rule::NegateNotEqualOp,
|
||||
(Flake8Simplify, "208") => Rule::DoubleNegation,
|
||||
@@ -347,15 +349,15 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<Rule> {
|
||||
(Flake8Simplify, "222") => Rule::ExprOrTrue,
|
||||
(Flake8Simplify, "223") => Rule::ExprAndFalse,
|
||||
(Flake8Simplify, "300") => Rule::YodaConditions,
|
||||
(Flake8Simplify, "401") => Rule::DictGetWithDefault,
|
||||
(Flake8Simplify, "401") => Rule::IfElseBlockInsteadOfDictGet,
|
||||
|
||||
// pyupgrade
|
||||
(Pyupgrade, "001") => Rule::UselessMetaclassType,
|
||||
(Pyupgrade, "003") => Rule::TypeOfPrimitive,
|
||||
(Pyupgrade, "004") => Rule::UselessObjectInheritance,
|
||||
(Pyupgrade, "005") => Rule::DeprecatedUnittestAlias,
|
||||
(Pyupgrade, "006") => Rule::DeprecatedCollectionType,
|
||||
(Pyupgrade, "007") => Rule::TypingUnion,
|
||||
(Pyupgrade, "006") => Rule::NonPEP585Annotation,
|
||||
(Pyupgrade, "007") => Rule::NonPEP604Annotation,
|
||||
(Pyupgrade, "008") => Rule::SuperCallWithParameters,
|
||||
(Pyupgrade, "009") => Rule::UTF8EncodingDeclaration,
|
||||
(Pyupgrade, "010") => Rule::UnnecessaryFutureImport,
|
||||
@@ -370,32 +372,32 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<Rule> {
|
||||
(Pyupgrade, "020") => Rule::OpenAlias,
|
||||
(Pyupgrade, "021") => Rule::ReplaceUniversalNewlines,
|
||||
(Pyupgrade, "022") => Rule::ReplaceStdoutStderr,
|
||||
(Pyupgrade, "023") => Rule::RewriteCElementTree,
|
||||
(Pyupgrade, "023") => Rule::DeprecatedCElementTree,
|
||||
(Pyupgrade, "024") => Rule::OSErrorAlias,
|
||||
(Pyupgrade, "025") => Rule::RewriteUnicodeLiteral,
|
||||
(Pyupgrade, "026") => Rule::RewriteMockImport,
|
||||
(Pyupgrade, "027") => Rule::RewriteListComprehension,
|
||||
(Pyupgrade, "028") => Rule::RewriteYieldFrom,
|
||||
(Pyupgrade, "025") => Rule::UnicodeKindPrefix,
|
||||
(Pyupgrade, "026") => Rule::DeprecatedMockImport,
|
||||
(Pyupgrade, "027") => Rule::UnpackedListComprehension,
|
||||
(Pyupgrade, "028") => Rule::YieldInForLoop,
|
||||
(Pyupgrade, "029") => Rule::UnnecessaryBuiltinImport,
|
||||
(Pyupgrade, "030") => Rule::FormatLiterals,
|
||||
(Pyupgrade, "031") => Rule::PrintfStringFormatting,
|
||||
(Pyupgrade, "032") => Rule::FString,
|
||||
(Pyupgrade, "033") => Rule::FunctoolsCache,
|
||||
(Pyupgrade, "033") => Rule::LRUCacheWithMaxsizeNone,
|
||||
(Pyupgrade, "034") => Rule::ExtraneousParentheses,
|
||||
(Pyupgrade, "035") => Rule::DeprecatedImport,
|
||||
(Pyupgrade, "036") => Rule::OutdatedVersionBlock,
|
||||
(Pyupgrade, "037") => Rule::QuotedAnnotation,
|
||||
(Pyupgrade, "038") => Rule::IsinstanceWithTuple,
|
||||
(Pyupgrade, "038") => Rule::NonPEP604Isinstance,
|
||||
|
||||
// pydocstyle
|
||||
(Pydocstyle, "100") => Rule::PublicModule,
|
||||
(Pydocstyle, "101") => Rule::PublicClass,
|
||||
(Pydocstyle, "102") => Rule::PublicMethod,
|
||||
(Pydocstyle, "103") => Rule::PublicFunction,
|
||||
(Pydocstyle, "104") => Rule::PublicPackage,
|
||||
(Pydocstyle, "105") => Rule::MagicMethod,
|
||||
(Pydocstyle, "106") => Rule::PublicNestedClass,
|
||||
(Pydocstyle, "107") => Rule::PublicInit,
|
||||
(Pydocstyle, "100") => Rule::UndocumentedPublicModule,
|
||||
(Pydocstyle, "101") => Rule::UndocumentedPublicClass,
|
||||
(Pydocstyle, "102") => Rule::UndocumentedPublicMethod,
|
||||
(Pydocstyle, "103") => Rule::UndocumentedPublicFunction,
|
||||
(Pydocstyle, "104") => Rule::UndocumentedPublicPackage,
|
||||
(Pydocstyle, "105") => Rule::UndocumentedMagicMethod,
|
||||
(Pydocstyle, "106") => Rule::UndocumentedPublicNestedClass,
|
||||
(Pydocstyle, "107") => Rule::UndocumentedPublicInit,
|
||||
(Pydocstyle, "200") => Rule::FitsOnOneLine,
|
||||
(Pydocstyle, "201") => Rule::NoBlankLineBeforeFunction,
|
||||
(Pydocstyle, "202") => Rule::NoBlankLineAfterFunction,
|
||||
@@ -403,11 +405,11 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<Rule> {
|
||||
(Pydocstyle, "204") => Rule::OneBlankLineAfterClass,
|
||||
(Pydocstyle, "205") => Rule::BlankLineAfterSummary,
|
||||
(Pydocstyle, "206") => Rule::IndentWithSpaces,
|
||||
(Pydocstyle, "207") => Rule::NoUnderIndentation,
|
||||
(Pydocstyle, "208") => Rule::NoOverIndentation,
|
||||
(Pydocstyle, "207") => Rule::UnderIndentation,
|
||||
(Pydocstyle, "208") => Rule::OverIndentation,
|
||||
(Pydocstyle, "209") => Rule::NewLineAfterLastParagraph,
|
||||
(Pydocstyle, "210") => Rule::NoSurroundingWhitespace,
|
||||
(Pydocstyle, "211") => Rule::NoBlankLineBeforeClass,
|
||||
(Pydocstyle, "210") => Rule::SurroundingWhitespace,
|
||||
(Pydocstyle, "211") => Rule::BlankLineBeforeClass,
|
||||
(Pydocstyle, "212") => Rule::MultiLineSummaryFirstLine,
|
||||
(Pydocstyle, "213") => Rule::MultiLineSummarySecondLine,
|
||||
(Pydocstyle, "214") => Rule::SectionNotOverIndented,
|
||||
@@ -424,9 +426,9 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<Rule> {
|
||||
(Pydocstyle, "407") => Rule::DashedUnderlineAfterSection,
|
||||
(Pydocstyle, "408") => Rule::SectionUnderlineAfterName,
|
||||
(Pydocstyle, "409") => Rule::SectionUnderlineMatchesSectionLength,
|
||||
(Pydocstyle, "410") => Rule::BlankLineAfterSection,
|
||||
(Pydocstyle, "411") => Rule::BlankLineBeforeSection,
|
||||
(Pydocstyle, "412") => Rule::NoBlankLinesBetweenHeaderAndContent,
|
||||
(Pydocstyle, "410") => Rule::NoBlankLineAfterSection,
|
||||
(Pydocstyle, "411") => Rule::NoBlankLineBeforeSection,
|
||||
(Pydocstyle, "412") => Rule::BlankLinesBetweenHeaderAndContent,
|
||||
(Pydocstyle, "413") => Rule::BlankLineAfterLastSection,
|
||||
(Pydocstyle, "414") => Rule::EmptyDocstringSection,
|
||||
(Pydocstyle, "415") => Rule::EndsInPunctuation,
|
||||
@@ -468,16 +470,37 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<Rule> {
|
||||
(Flake8Bandit, "105") => Rule::HardcodedPasswordString,
|
||||
(Flake8Bandit, "106") => Rule::HardcodedPasswordFuncArg,
|
||||
(Flake8Bandit, "107") => Rule::HardcodedPasswordDefault,
|
||||
(Flake8Bandit, "608") => Rule::HardcodedSQLExpression,
|
||||
(Flake8Bandit, "108") => Rule::HardcodedTempFile,
|
||||
(Flake8Bandit, "110") => Rule::TryExceptPass,
|
||||
(Flake8Bandit, "112") => Rule::TryExceptContinue,
|
||||
(Flake8Bandit, "113") => Rule::RequestWithoutTimeout,
|
||||
(Flake8Bandit, "301") => Rule::SuspiciousPickleUsage,
|
||||
(Flake8Bandit, "302") => Rule::SuspiciousMarshalUsage,
|
||||
(Flake8Bandit, "303") => Rule::SuspiciousInsecureHashUsage,
|
||||
(Flake8Bandit, "304") => Rule::SuspiciousInsecureCipherUsage,
|
||||
(Flake8Bandit, "305") => Rule::SuspiciousInsecureCipherModeUsage,
|
||||
(Flake8Bandit, "306") => Rule::SuspiciousMktempUsage,
|
||||
(Flake8Bandit, "307") => Rule::SuspiciousEvalUsage,
|
||||
(Flake8Bandit, "308") => Rule::SuspiciousMarkSafeUsage,
|
||||
(Flake8Bandit, "310") => Rule::SuspiciousURLOpenUsage,
|
||||
(Flake8Bandit, "311") => Rule::SuspiciousNonCryptographicRandomUsage,
|
||||
(Flake8Bandit, "312") => Rule::SuspiciousTelnetUsage,
|
||||
(Flake8Bandit, "313") => Rule::SuspiciousXMLCElementTreeUsage,
|
||||
(Flake8Bandit, "314") => Rule::SuspiciousXMLElementTreeUsage,
|
||||
(Flake8Bandit, "315") => Rule::SuspiciousXMLExpatReaderUsage,
|
||||
(Flake8Bandit, "316") => Rule::SuspiciousXMLExpatBuilderUsage,
|
||||
(Flake8Bandit, "317") => Rule::SuspiciousXMLSaxUsage,
|
||||
(Flake8Bandit, "318") => Rule::SuspiciousXMLMiniDOMUsage,
|
||||
(Flake8Bandit, "319") => Rule::SuspiciousXMLPullDOMUsage,
|
||||
(Flake8Bandit, "320") => Rule::SuspiciousXMLETreeUsage,
|
||||
(Flake8Bandit, "321") => Rule::SuspiciousFTPLibUsage,
|
||||
(Flake8Bandit, "323") => Rule::SuspiciousUnverifiedContextUsage,
|
||||
(Flake8Bandit, "324") => Rule::HashlibInsecureHashFunction,
|
||||
(Flake8Bandit, "501") => Rule::RequestWithNoCertValidation,
|
||||
(Flake8Bandit, "506") => Rule::UnsafeYAMLLoad,
|
||||
(Flake8Bandit, "508") => Rule::SnmpInsecureVersion,
|
||||
(Flake8Bandit, "509") => Rule::SnmpWeakCryptography,
|
||||
(Flake8Bandit, "608") => Rule::HardcodedSQLExpression,
|
||||
(Flake8Bandit, "612") => Rule::LoggingConfigInsecureListen,
|
||||
(Flake8Bandit, "701") => Rule::Jinja2AutoescapeFalse,
|
||||
|
||||
@@ -508,24 +531,24 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<Rule> {
|
||||
(Flake8Datetimez, "012") => Rule::CallDateFromtimestamp,
|
||||
|
||||
// pygrep-hooks
|
||||
(PygrepHooks, "001") => Rule::NoEval,
|
||||
(PygrepHooks, "001") => Rule::Eval,
|
||||
(PygrepHooks, "002") => Rule::DeprecatedLogWarn,
|
||||
(PygrepHooks, "003") => Rule::BlanketTypeIgnore,
|
||||
(PygrepHooks, "004") => Rule::BlanketNOQA,
|
||||
|
||||
// pandas-vet
|
||||
(PandasVet, "002") => Rule::UseOfInplaceArgument,
|
||||
(PandasVet, "003") => Rule::UseOfDotIsNull,
|
||||
(PandasVet, "004") => Rule::UseOfDotNotNull,
|
||||
(PandasVet, "007") => Rule::UseOfDotIx,
|
||||
(PandasVet, "008") => Rule::UseOfDotAt,
|
||||
(PandasVet, "009") => Rule::UseOfDotIat,
|
||||
(PandasVet, "010") => Rule::UseOfDotPivotOrUnstack,
|
||||
(PandasVet, "011") => Rule::UseOfDotValues,
|
||||
(PandasVet, "012") => Rule::UseOfDotReadTable,
|
||||
(PandasVet, "013") => Rule::UseOfDotStack,
|
||||
(PandasVet, "015") => Rule::UseOfPdMerge,
|
||||
(PandasVet, "901") => Rule::DfIsABadVariableName,
|
||||
(PandasVet, "002") => Rule::PandasUseOfInplaceArgument,
|
||||
(PandasVet, "003") => Rule::PandasUseOfDotIsNull,
|
||||
(PandasVet, "004") => Rule::PandasUseOfDotNotNull,
|
||||
(PandasVet, "007") => Rule::PandasUseOfDotIx,
|
||||
(PandasVet, "008") => Rule::PandasUseOfDotAt,
|
||||
(PandasVet, "009") => Rule::PandasUseOfDotIat,
|
||||
(PandasVet, "010") => Rule::PandasUseOfDotPivotOrUnstack,
|
||||
(PandasVet, "011") => Rule::PandasUseOfDotValues,
|
||||
(PandasVet, "012") => Rule::PandasUseOfDotReadTable,
|
||||
(PandasVet, "013") => Rule::PandasUseOfDotStack,
|
||||
(PandasVet, "015") => Rule::PandasUseOfPdMerge,
|
||||
(PandasVet, "901") => Rule::PandasDfVariableName,
|
||||
|
||||
// flake8-errmsg
|
||||
(Flake8ErrMsg, "101") => Rule::RawStringInException,
|
||||
@@ -533,58 +556,58 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<Rule> {
|
||||
(Flake8ErrMsg, "103") => Rule::DotFormatInException,
|
||||
|
||||
// flake8-pyi
|
||||
(Flake8Pyi, "001") => Rule::PrefixTypeParams,
|
||||
(Flake8Pyi, "001") => Rule::UnprefixedTypeParam,
|
||||
(Flake8Pyi, "006") => Rule::BadVersionInfoComparison,
|
||||
(Flake8Pyi, "007") => Rule::UnrecognizedPlatformCheck,
|
||||
(Flake8Pyi, "008") => Rule::UnrecognizedPlatformName,
|
||||
(Flake8Pyi, "009") => Rule::PassStatementStubBody,
|
||||
(Flake8Pyi, "010") => Rule::NonEmptyStubBody,
|
||||
(Flake8Pyi, "011") => Rule::TypedArgumentSimpleDefaults,
|
||||
(Flake8Pyi, "014") => Rule::ArgumentSimpleDefaults,
|
||||
(Flake8Pyi, "011") => Rule::TypedArgumentDefaultInStub,
|
||||
(Flake8Pyi, "014") => Rule::ArgumentDefaultInStub,
|
||||
(Flake8Pyi, "021") => Rule::DocstringInStub,
|
||||
(Flake8Pyi, "033") => Rule::TypeCommentInStub,
|
||||
|
||||
// flake8-pytest-style
|
||||
(Flake8PytestStyle, "001") => Rule::IncorrectFixtureParenthesesStyle,
|
||||
(Flake8PytestStyle, "002") => Rule::FixturePositionalArgs,
|
||||
(Flake8PytestStyle, "003") => Rule::ExtraneousScopeFunction,
|
||||
(Flake8PytestStyle, "004") => Rule::MissingFixtureNameUnderscore,
|
||||
(Flake8PytestStyle, "005") => Rule::IncorrectFixtureNameUnderscore,
|
||||
(Flake8PytestStyle, "006") => Rule::ParametrizeNamesWrongType,
|
||||
(Flake8PytestStyle, "007") => Rule::ParametrizeValuesWrongType,
|
||||
(Flake8PytestStyle, "008") => Rule::PatchWithLambda,
|
||||
(Flake8PytestStyle, "009") => Rule::UnittestAssertion,
|
||||
(Flake8PytestStyle, "010") => Rule::RaisesWithoutException,
|
||||
(Flake8PytestStyle, "011") => Rule::RaisesTooBroad,
|
||||
(Flake8PytestStyle, "012") => Rule::RaisesWithMultipleStatements,
|
||||
(Flake8PytestStyle, "013") => Rule::IncorrectPytestImport,
|
||||
(Flake8PytestStyle, "015") => Rule::AssertAlwaysFalse,
|
||||
(Flake8PytestStyle, "016") => Rule::FailWithoutMessage,
|
||||
(Flake8PytestStyle, "017") => Rule::AssertInExcept,
|
||||
(Flake8PytestStyle, "018") => Rule::CompositeAssertion,
|
||||
(Flake8PytestStyle, "019") => Rule::FixtureParamWithoutValue,
|
||||
(Flake8PytestStyle, "020") => Rule::DeprecatedYieldFixture,
|
||||
(Flake8PytestStyle, "021") => Rule::FixtureFinalizerCallback,
|
||||
(Flake8PytestStyle, "022") => Rule::UselessYieldFixture,
|
||||
(Flake8PytestStyle, "023") => Rule::IncorrectMarkParenthesesStyle,
|
||||
(Flake8PytestStyle, "024") => Rule::UnnecessaryAsyncioMarkOnFixture,
|
||||
(Flake8PytestStyle, "025") => Rule::ErroneousUseFixturesOnFixture,
|
||||
(Flake8PytestStyle, "026") => Rule::UseFixturesWithoutParameters,
|
||||
(Flake8PytestStyle, "001") => Rule::PytestFixtureIncorrectParenthesesStyle,
|
||||
(Flake8PytestStyle, "002") => Rule::PytestFixturePositionalArgs,
|
||||
(Flake8PytestStyle, "003") => Rule::PytestExtraneousScopeFunction,
|
||||
(Flake8PytestStyle, "004") => Rule::PytestMissingFixtureNameUnderscore,
|
||||
(Flake8PytestStyle, "005") => Rule::PytestIncorrectFixtureNameUnderscore,
|
||||
(Flake8PytestStyle, "006") => Rule::PytestParametrizeNamesWrongType,
|
||||
(Flake8PytestStyle, "007") => Rule::PytestParametrizeValuesWrongType,
|
||||
(Flake8PytestStyle, "008") => Rule::PytestPatchWithLambda,
|
||||
(Flake8PytestStyle, "009") => Rule::PytestUnittestAssertion,
|
||||
(Flake8PytestStyle, "010") => Rule::PytestRaisesWithoutException,
|
||||
(Flake8PytestStyle, "011") => Rule::PytestRaisesTooBroad,
|
||||
(Flake8PytestStyle, "012") => Rule::PytestRaisesWithMultipleStatements,
|
||||
(Flake8PytestStyle, "013") => Rule::PytestIncorrectPytestImport,
|
||||
(Flake8PytestStyle, "015") => Rule::PytestAssertAlwaysFalse,
|
||||
(Flake8PytestStyle, "016") => Rule::PytestFailWithoutMessage,
|
||||
(Flake8PytestStyle, "017") => Rule::PytestAssertInExcept,
|
||||
(Flake8PytestStyle, "018") => Rule::PytestCompositeAssertion,
|
||||
(Flake8PytestStyle, "019") => Rule::PytestFixtureParamWithoutValue,
|
||||
(Flake8PytestStyle, "020") => Rule::PytestDeprecatedYieldFixture,
|
||||
(Flake8PytestStyle, "021") => Rule::PytestFixtureFinalizerCallback,
|
||||
(Flake8PytestStyle, "022") => Rule::PytestUselessYieldFixture,
|
||||
(Flake8PytestStyle, "023") => Rule::PytestIncorrectMarkParenthesesStyle,
|
||||
(Flake8PytestStyle, "024") => Rule::PytestUnnecessaryAsyncioMarkOnFixture,
|
||||
(Flake8PytestStyle, "025") => Rule::PytestErroneousUseFixturesOnFixture,
|
||||
(Flake8PytestStyle, "026") => Rule::PytestUseFixturesWithoutParameters,
|
||||
|
||||
// flake8-pie
|
||||
(Flake8Pie, "790") => Rule::UnnecessaryPass,
|
||||
(Flake8Pie, "794") => Rule::DupeClassFieldDefinitions,
|
||||
(Flake8Pie, "796") => Rule::PreferUniqueEnums,
|
||||
(Flake8Pie, "794") => Rule::DuplicateClassFieldDefinition,
|
||||
(Flake8Pie, "796") => Rule::NonUniqueEnums,
|
||||
(Flake8Pie, "800") => Rule::UnnecessarySpread,
|
||||
(Flake8Pie, "802") => Rule::UnnecessaryComprehensionAnyAll,
|
||||
(Flake8Pie, "804") => Rule::UnnecessaryDictKwargs,
|
||||
(Flake8Pie, "807") => Rule::PreferListBuiltin,
|
||||
(Flake8Pie, "810") => Rule::SingleStartsEndsWith,
|
||||
(Flake8Pie, "807") => Rule::ReimplementedListBuiltin,
|
||||
(Flake8Pie, "810") => Rule::MultipleStartsEndsWith,
|
||||
|
||||
// flake8-commas
|
||||
(Flake8Commas, "812") => Rule::TrailingCommaMissing,
|
||||
(Flake8Commas, "818") => Rule::TrailingCommaOnBareTupleProhibited,
|
||||
(Flake8Commas, "819") => Rule::TrailingCommaProhibited,
|
||||
(Flake8Commas, "812") => Rule::MissingTrailingComma,
|
||||
(Flake8Commas, "818") => Rule::TrailingCommaOnBareTuple,
|
||||
(Flake8Commas, "819") => Rule::ProhibitedTrailingComma,
|
||||
|
||||
// flake8-no-pep420
|
||||
(Flake8NoPep420, "001") => Rule::ImplicitNamespacePackage,
|
||||
@@ -592,9 +615,9 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<Rule> {
|
||||
// flake8-executable
|
||||
(Flake8Executable, "001") => Rule::ShebangNotExecutable,
|
||||
(Flake8Executable, "002") => Rule::ShebangMissingExecutableFile,
|
||||
(Flake8Executable, "003") => Rule::ShebangPython,
|
||||
(Flake8Executable, "004") => Rule::ShebangWhitespace,
|
||||
(Flake8Executable, "005") => Rule::ShebangNewline,
|
||||
(Flake8Executable, "003") => Rule::ShebangMissingPython,
|
||||
(Flake8Executable, "004") => Rule::ShebangLeadingWhitespace,
|
||||
(Flake8Executable, "005") => Rule::ShebangNotFirstLine,
|
||||
|
||||
// flake8-type-checking
|
||||
(Flake8TypeChecking, "001") => Rule::TypingOnlyFirstPartyImport,
|
||||
@@ -606,7 +629,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<Rule> {
|
||||
// tryceratops
|
||||
(Tryceratops, "002") => Rule::RaiseVanillaClass,
|
||||
(Tryceratops, "003") => Rule::RaiseVanillaArgs,
|
||||
(Tryceratops, "004") => Rule::PreferTypeError,
|
||||
(Tryceratops, "004") => Rule::TypeCheckWithoutTypeError,
|
||||
(Tryceratops, "200") => Rule::ReraiseNoCause,
|
||||
(Tryceratops, "201") => Rule::VerboseRaise,
|
||||
(Tryceratops, "300") => Rule::TryConsiderElse,
|
||||
@@ -615,31 +638,31 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<Rule> {
|
||||
(Tryceratops, "401") => Rule::VerboseLogMessage,
|
||||
|
||||
// flake8-use-pathlib
|
||||
(Flake8UsePathlib, "100") => Rule::PathlibAbspath,
|
||||
(Flake8UsePathlib, "101") => Rule::PathlibChmod,
|
||||
(Flake8UsePathlib, "102") => Rule::PathlibMkdir,
|
||||
(Flake8UsePathlib, "103") => Rule::PathlibMakedirs,
|
||||
(Flake8UsePathlib, "104") => Rule::PathlibRename,
|
||||
(Flake8UsePathlib, "100") => Rule::OsPathAbspath,
|
||||
(Flake8UsePathlib, "101") => Rule::OsChmod,
|
||||
(Flake8UsePathlib, "102") => Rule::OsMkdir,
|
||||
(Flake8UsePathlib, "103") => Rule::OsMakedirs,
|
||||
(Flake8UsePathlib, "104") => Rule::OsRename,
|
||||
(Flake8UsePathlib, "105") => Rule::PathlibReplace,
|
||||
(Flake8UsePathlib, "106") => Rule::PathlibRmdir,
|
||||
(Flake8UsePathlib, "107") => Rule::PathlibRemove,
|
||||
(Flake8UsePathlib, "108") => Rule::PathlibUnlink,
|
||||
(Flake8UsePathlib, "109") => Rule::PathlibGetcwd,
|
||||
(Flake8UsePathlib, "110") => Rule::PathlibExists,
|
||||
(Flake8UsePathlib, "111") => Rule::PathlibExpanduser,
|
||||
(Flake8UsePathlib, "112") => Rule::PathlibIsDir,
|
||||
(Flake8UsePathlib, "113") => Rule::PathlibIsFile,
|
||||
(Flake8UsePathlib, "114") => Rule::PathlibIsLink,
|
||||
(Flake8UsePathlib, "115") => Rule::PathlibReadlink,
|
||||
(Flake8UsePathlib, "116") => Rule::PathlibStat,
|
||||
(Flake8UsePathlib, "117") => Rule::PathlibIsAbs,
|
||||
(Flake8UsePathlib, "118") => Rule::PathlibJoin,
|
||||
(Flake8UsePathlib, "119") => Rule::PathlibBasename,
|
||||
(Flake8UsePathlib, "120") => Rule::PathlibDirname,
|
||||
(Flake8UsePathlib, "121") => Rule::PathlibSamefile,
|
||||
(Flake8UsePathlib, "122") => Rule::PathlibSplitext,
|
||||
(Flake8UsePathlib, "123") => Rule::PathlibOpen,
|
||||
(Flake8UsePathlib, "124") => Rule::PathlibPyPath,
|
||||
(Flake8UsePathlib, "106") => Rule::OsRmdir,
|
||||
(Flake8UsePathlib, "107") => Rule::OsRemove,
|
||||
(Flake8UsePathlib, "108") => Rule::OsUnlink,
|
||||
(Flake8UsePathlib, "109") => Rule::OsGetcwd,
|
||||
(Flake8UsePathlib, "110") => Rule::OsPathExists,
|
||||
(Flake8UsePathlib, "111") => Rule::OsPathExpanduser,
|
||||
(Flake8UsePathlib, "112") => Rule::OsPathIsdir,
|
||||
(Flake8UsePathlib, "113") => Rule::OsPathIsfile,
|
||||
(Flake8UsePathlib, "114") => Rule::OsPathIslink,
|
||||
(Flake8UsePathlib, "115") => Rule::OsReadlink,
|
||||
(Flake8UsePathlib, "116") => Rule::OsStat,
|
||||
(Flake8UsePathlib, "117") => Rule::OsPathIsabs,
|
||||
(Flake8UsePathlib, "118") => Rule::OsPathJoin,
|
||||
(Flake8UsePathlib, "119") => Rule::OsPathBasename,
|
||||
(Flake8UsePathlib, "120") => Rule::OsPathDirname,
|
||||
(Flake8UsePathlib, "121") => Rule::OsPathSamefile,
|
||||
(Flake8UsePathlib, "122") => Rule::OsPathSplitext,
|
||||
(Flake8UsePathlib, "123") => Rule::BuiltinOpen,
|
||||
(Flake8UsePathlib, "124") => Rule::PyPath,
|
||||
|
||||
// flake8-logging-format
|
||||
(Flake8LoggingFormat, "001") => Rule::LoggingStringFormat,
|
||||
@@ -665,18 +688,19 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<Rule> {
|
||||
(Ruff, "001") => Rule::AmbiguousUnicodeCharacterString,
|
||||
(Ruff, "002") => Rule::AmbiguousUnicodeCharacterDocstring,
|
||||
(Ruff, "003") => Rule::AmbiguousUnicodeCharacterComment,
|
||||
(Ruff, "005") => Rule::UnpackInsteadOfConcatenatingToCollectionLiteral,
|
||||
(Ruff, "005") => Rule::CollectionLiteralConcatenation,
|
||||
(Ruff, "006") => Rule::AsyncioDanglingTask,
|
||||
(Ruff, "007") => Rule::PairwiseOverZipped,
|
||||
(Ruff, "100") => Rule::UnusedNOQA,
|
||||
|
||||
// flake8-django
|
||||
(Flake8Django, "001") => Rule::NullableModelStringField,
|
||||
(Flake8Django, "003") => Rule::LocalsInRenderFunction,
|
||||
(Flake8Django, "006") => Rule::ExcludeWithModelForm,
|
||||
(Flake8Django, "007") => Rule::AllWithModelForm,
|
||||
(Flake8Django, "008") => Rule::ModelWithoutDunderStr,
|
||||
(Flake8Django, "013") => Rule::NonLeadingReceiverDecorator,
|
||||
(Flake8Django, "001") => Rule::DjangoNullableModelStringField,
|
||||
(Flake8Django, "003") => Rule::DjangoLocalsInRenderFunction,
|
||||
(Flake8Django, "006") => Rule::DjangoExcludeWithModelForm,
|
||||
(Flake8Django, "007") => Rule::DjangoAllWithModelForm,
|
||||
(Flake8Django, "008") => Rule::DjangoModelWithoutDunderStr,
|
||||
(Flake8Django, "012") => Rule::DjangoUnorderedBodyContentInModel,
|
||||
(Flake8Django, "013") => Rule::DjangoNonLeadingReceiverDecorator,
|
||||
|
||||
_ => return None,
|
||||
})
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use anyhow::{bail, Result};
|
||||
use libcst_native::{
|
||||
Call, Comparison, Expr, Expression, Import, ImportFrom, Module, SmallStatement, Statement,
|
||||
Attribute, Call, Comparison, Dict, Expr, Expression, Import, ImportFrom, Module, SimpleString,
|
||||
SmallStatement, Statement,
|
||||
};
|
||||
|
||||
pub fn match_module(module_text: &str) -> Result<Module> {
|
||||
@@ -70,3 +71,31 @@ pub fn match_comparison<'a, 'b>(
|
||||
bail!("Expected Expression::Comparison")
|
||||
}
|
||||
}
|
||||
|
||||
pub fn match_dict<'a, 'b>(expression: &'a mut Expression<'b>) -> Result<&'a mut Dict<'b>> {
|
||||
if let Expression::Dict(dict) = expression {
|
||||
Ok(dict)
|
||||
} else {
|
||||
bail!("Expected Expression::Dict")
|
||||
}
|
||||
}
|
||||
|
||||
pub fn match_attribute<'a, 'b>(
|
||||
expression: &'a mut Expression<'b>,
|
||||
) -> Result<&'a mut Attribute<'b>> {
|
||||
if let Expression::Attribute(attribute) = expression {
|
||||
Ok(attribute)
|
||||
} else {
|
||||
bail!("Expected Expression::Attribute")
|
||||
}
|
||||
}
|
||||
|
||||
pub fn match_simple_string<'a, 'b>(
|
||||
expression: &'a mut Expression<'b>,
|
||||
) -> Result<&'a mut SimpleString<'b>> {
|
||||
if let Expression::SimpleString(simple_string) = expression {
|
||||
Ok(simple_string)
|
||||
} else {
|
||||
bail!("Expected Expression::SimpleString")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,15 +2,18 @@
|
||||
|
||||
use rustpython_parser::ast::{Constant, Expr, ExprKind, Stmt, StmtKind};
|
||||
|
||||
use crate::docstrings::definition::{Definition, DefinitionKind, Documentable};
|
||||
use ruff_python_ast::visibility::{Modifier, VisibleScope};
|
||||
|
||||
use crate::docstrings::definition::{Definition, DefinitionKind, Documentable};
|
||||
|
||||
/// Extract a docstring from a function or class body.
|
||||
pub fn docstring_from(suite: &[Stmt]) -> Option<&Expr> {
|
||||
let stmt = suite.first()?;
|
||||
// Require the docstring to be a standalone expression.
|
||||
let StmtKind::Expr { value } = &stmt.node else {
|
||||
return None;
|
||||
};
|
||||
// Only match strings.
|
||||
if !matches!(
|
||||
&value.node,
|
||||
ExprKind::Constant {
|
||||
|
||||
@@ -4,9 +4,8 @@ use anyhow::{anyhow, Result};
|
||||
use globset::GlobMatcher;
|
||||
use log::debug;
|
||||
use path_absolutize::{path_dedot, Absolutize};
|
||||
use rustc_hash::FxHashSet;
|
||||
|
||||
use crate::registry::Rule;
|
||||
use crate::registry::RuleSet;
|
||||
|
||||
/// Extract the absolute path and basename (as strings) from a Path.
|
||||
pub fn extract_path_names(path: &Path) -> Result<(&str, &str)> {
|
||||
@@ -24,35 +23,34 @@ 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(
|
||||
path: &Path,
|
||||
pattern_code_pairs: &[(GlobMatcher, GlobMatcher, FxHashSet<Rule>)],
|
||||
) -> FxHashSet<Rule> {
|
||||
pattern_code_pairs: &[(GlobMatcher, GlobMatcher, RuleSet)],
|
||||
) -> RuleSet {
|
||||
let (file_path, file_basename) = extract_path_names(path).expect("Unable to parse filename");
|
||||
|
||||
pattern_code_pairs
|
||||
.iter()
|
||||
.filter_map(|(absolute, basename, codes)| {
|
||||
.filter_map(|(absolute, basename, rules)| {
|
||||
if basename.is_match(file_basename) {
|
||||
debug!(
|
||||
"Adding per-file ignores for {:?} due to basename match on {:?}: {:?}",
|
||||
path,
|
||||
basename.glob().regex(),
|
||||
codes
|
||||
rules
|
||||
);
|
||||
Some(codes)
|
||||
Some(rules)
|
||||
} else if absolute.is_match(file_path) {
|
||||
debug!(
|
||||
"Adding per-file ignores for {:?} due to absolute match on {:?}: {:?}",
|
||||
path,
|
||||
absolute.glob().regex(),
|
||||
codes
|
||||
rules
|
||||
);
|
||||
Some(codes)
|
||||
Some(rules)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.flatten()
|
||||
.copied()
|
||||
.collect()
|
||||
}
|
||||
|
||||
|
||||
7
crates/ruff/src/jupyter/mod.rs
Normal file
7
crates/ruff/src/jupyter/mod.rs
Normal file
@@ -0,0 +1,7 @@
|
||||
//! Utils for reading and writing jupyter notebooks
|
||||
|
||||
mod notebook;
|
||||
mod schema;
|
||||
|
||||
pub use notebook::*;
|
||||
pub use schema::*;
|
||||
283
crates/ruff/src/jupyter/notebook.rs
Normal file
283
crates/ruff/src/jupyter/notebook.rs
Normal file
@@ -0,0 +1,283 @@
|
||||
use std::fs::File;
|
||||
use std::io::{BufReader, BufWriter};
|
||||
use std::iter;
|
||||
use std::path::Path;
|
||||
|
||||
use serde::Serialize;
|
||||
use serde_json::error::Category;
|
||||
|
||||
use ruff_diagnostics::Diagnostic;
|
||||
use ruff_python_ast::types::Range;
|
||||
|
||||
use crate::jupyter::{CellType, JupyterNotebook, SourceValue};
|
||||
use crate::rules::pycodestyle::rules::SyntaxError;
|
||||
use crate::IOError;
|
||||
|
||||
pub const JUPYTER_NOTEBOOK_EXT: &str = "ipynb";
|
||||
|
||||
/// Jupyter Notebook indexing table
|
||||
///
|
||||
/// When we lint a jupyter notebook, we have to translate the row/column based on
|
||||
/// [`crate::message::Location`]
|
||||
/// to jupyter notebook cell/row/column.
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
pub struct JupyterIndex {
|
||||
/// Enter a row (1-based), get back the cell (1-based)
|
||||
pub row_to_cell: Vec<u32>,
|
||||
/// Enter a row (1-based), get back the cell (1-based)
|
||||
pub row_to_row_in_cell: Vec<u32>,
|
||||
}
|
||||
|
||||
/// Return `true` if the [`Path`] appears to be that of a jupyter notebook file (`.ipynb`).
|
||||
pub fn is_jupyter_notebook(path: &Path) -> bool {
|
||||
path.extension()
|
||||
.map_or(false, |ext| ext == JUPYTER_NOTEBOOK_EXT)
|
||||
// For now this is feature gated here, the long term solution depends on
|
||||
// https://github.com/charliermarsh/ruff/issues/3410
|
||||
&& cfg!(feature = "jupyter_notebook")
|
||||
}
|
||||
|
||||
impl JupyterNotebook {
|
||||
/// See also the black implementation
|
||||
/// <https://github.com/psf/black/blob/69ca0a4c7a365c5f5eea519a90980bab72cab764/src/black/__init__.py#L1017-L1046>
|
||||
pub fn read(path: &Path) -> Result<Self, Box<Diagnostic>> {
|
||||
let reader = BufReader::new(File::open(path).map_err(|err| {
|
||||
Diagnostic::new(
|
||||
IOError {
|
||||
message: format!("{err}"),
|
||||
},
|
||||
Range::default(),
|
||||
)
|
||||
})?);
|
||||
let notebook: JupyterNotebook = match serde_json::from_reader(reader) {
|
||||
Ok(notebook) => notebook,
|
||||
Err(err) => {
|
||||
// Translate the error into a diagnostic
|
||||
return Err(Box::new({
|
||||
match err.classify() {
|
||||
Category::Io => Diagnostic::new(
|
||||
IOError {
|
||||
message: format!("{err}"),
|
||||
},
|
||||
Range::default(),
|
||||
),
|
||||
Category::Syntax | Category::Eof => {
|
||||
// Maybe someone saved the python sources (those with the `# %%` separator)
|
||||
// as jupyter notebook instead. Let's help them.
|
||||
let contents = std::fs::read_to_string(path).map_err(|err| {
|
||||
Diagnostic::new(
|
||||
IOError {
|
||||
message: format!("{err}"),
|
||||
},
|
||||
Range::default(),
|
||||
)
|
||||
})?;
|
||||
// Check if tokenizing was successful and the file is non-empty
|
||||
if (ruff_rustpython::tokenize(&contents))
|
||||
.last()
|
||||
.map_or(true, Result::is_err)
|
||||
{
|
||||
Diagnostic::new(
|
||||
SyntaxError {
|
||||
message: format!(
|
||||
"A Jupyter Notebook (.{JUPYTER_NOTEBOOK_EXT}) must internally be JSON, \
|
||||
but this file isn't valid JSON: {err}"
|
||||
),
|
||||
},
|
||||
Range::default(),
|
||||
)
|
||||
} else {
|
||||
Diagnostic::new(
|
||||
SyntaxError {
|
||||
message: format!(
|
||||
"Expected a Jupyter Notebook (.{JUPYTER_NOTEBOOK_EXT} extension), \
|
||||
which must be internally stored as JSON, \
|
||||
but found a Python source file: {err}"
|
||||
),
|
||||
},
|
||||
Range::default(),
|
||||
)
|
||||
}
|
||||
}
|
||||
Category::Data => {
|
||||
// We could try to read the schema version here but if this fails it's
|
||||
// a bug anyway
|
||||
Diagnostic::new(
|
||||
SyntaxError {
|
||||
message: format!(
|
||||
"This file does not match the schema expected of Jupyter Notebooks: {err}"
|
||||
),
|
||||
},
|
||||
Range::default(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
};
|
||||
|
||||
// v4 is what everybody uses
|
||||
if notebook.nbformat != 4 {
|
||||
// bail because we should have already failed at the json schema stage
|
||||
return Err(Box::new(Diagnostic::new(
|
||||
SyntaxError {
|
||||
message: format!(
|
||||
"Expected Jupyter Notebook format 4, found {}",
|
||||
notebook.nbformat
|
||||
),
|
||||
},
|
||||
Range::default(),
|
||||
)));
|
||||
}
|
||||
|
||||
Ok(notebook)
|
||||
}
|
||||
|
||||
/// Concatenates all cells into a single virtual file and builds an index that maps the content
|
||||
/// to notebook cell locations
|
||||
pub fn index(&self) -> (String, JupyterIndex) {
|
||||
let mut jupyter_index = JupyterIndex {
|
||||
// Enter a line number (1-based), get back the cell (1-based)
|
||||
// 0 index is just padding
|
||||
row_to_cell: vec![0],
|
||||
// Enter a line number (1-based), get back the row number in the cell (1-based)
|
||||
// 0 index is just padding
|
||||
row_to_row_in_cell: vec![0],
|
||||
};
|
||||
let size_hint = self
|
||||
.cells
|
||||
.iter()
|
||||
.filter(|cell| cell.cell_type == CellType::Code)
|
||||
.count();
|
||||
|
||||
let mut contents = Vec::with_capacity(size_hint);
|
||||
|
||||
for (pos, cell) in self
|
||||
.cells
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter(|(_pos, cell)| cell.cell_type == CellType::Code)
|
||||
{
|
||||
let cell_contents = match &cell.source {
|
||||
SourceValue::String(string) => {
|
||||
// TODO(konstin): is or isn't there a trailing newline per cell?
|
||||
// i've only seen these as array and never as string
|
||||
let line_count = u32::try_from(string.lines().count()).unwrap();
|
||||
jupyter_index.row_to_cell.extend(
|
||||
iter::repeat(u32::try_from(pos + 1).unwrap()).take(line_count as usize),
|
||||
);
|
||||
jupyter_index.row_to_row_in_cell.extend(1..=line_count);
|
||||
string.clone()
|
||||
}
|
||||
SourceValue::StringArray(string_array) => {
|
||||
jupyter_index.row_to_cell.extend(
|
||||
iter::repeat(u32::try_from(pos + 1).unwrap()).take(string_array.len()),
|
||||
);
|
||||
jupyter_index
|
||||
.row_to_row_in_cell
|
||||
.extend(1..=u32::try_from(string_array.len()).unwrap());
|
||||
// lines already end in a newline character
|
||||
string_array.join("")
|
||||
}
|
||||
};
|
||||
contents.push(cell_contents);
|
||||
}
|
||||
// The last line doesn't end in a newline character
|
||||
(contents.join("\n"), jupyter_index)
|
||||
}
|
||||
|
||||
/// Write back with an indent of 1, just like black
|
||||
pub fn write(&self, path: &Path) -> anyhow::Result<()> {
|
||||
let mut writer = BufWriter::new(File::create(path)?);
|
||||
// https://github.com/psf/black/blob/69ca0a4c7a365c5f5eea519a90980bab72cab764/src/black/__init__.py#LL1041
|
||||
let formatter = serde_json::ser::PrettyFormatter::with_indent(b" ");
|
||||
let mut ser = serde_json::Serializer::with_formatter(&mut writer, formatter);
|
||||
self.serialize(&mut ser)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use std::path::Path;
|
||||
|
||||
#[cfg(feature = "jupyter_notebook")]
|
||||
use crate::jupyter::is_jupyter_notebook;
|
||||
use crate::jupyter::{JupyterIndex, JupyterNotebook};
|
||||
|
||||
#[test]
|
||||
fn test_valid() {
|
||||
let path = Path::new("resources/test/fixtures/jupyter/valid.ipynb");
|
||||
assert!(JupyterNotebook::read(path).is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_r() {
|
||||
// We can load this, it will be filtered out later
|
||||
let path = Path::new("resources/test/fixtures/jupyter/R.ipynb");
|
||||
assert!(JupyterNotebook::read(path).is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_invalid() {
|
||||
let path = Path::new("resources/test/fixtures/jupyter/invalid_extension.ipynb");
|
||||
assert_eq!(
|
||||
JupyterNotebook::read(path).unwrap_err().kind.body,
|
||||
"SyntaxError: Expected a Jupyter Notebook (.ipynb extension), \
|
||||
which must be internally stored as JSON, \
|
||||
but found a Python source file: \
|
||||
expected value at line 1 column 1"
|
||||
);
|
||||
let path = Path::new("resources/test/fixtures/jupyter/not_json.ipynb");
|
||||
assert_eq!(
|
||||
JupyterNotebook::read(path).unwrap_err().kind.body,
|
||||
"SyntaxError: A Jupyter Notebook (.ipynb) must internally be JSON, \
|
||||
but this file isn't valid JSON: \
|
||||
expected value at line 1 column 1"
|
||||
);
|
||||
let path = Path::new("resources/test/fixtures/jupyter/wrong_schema.ipynb");
|
||||
assert_eq!(
|
||||
JupyterNotebook::read(path).unwrap_err().kind.body,
|
||||
"SyntaxError: This file does not match the schema expected of Jupyter Notebooks: \
|
||||
missing field `cells` at line 1 column 2"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "jupyter_notebook")]
|
||||
fn inclusions() {
|
||||
let path = Path::new("foo/bar/baz");
|
||||
assert!(!is_jupyter_notebook(path));
|
||||
|
||||
let path = Path::new("foo/bar/baz.ipynb");
|
||||
assert!(is_jupyter_notebook(path));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_concat_notebook() {
|
||||
let path = Path::new("resources/test/fixtures/jupyter/valid.ipynb");
|
||||
let notebook = JupyterNotebook::read(path).unwrap();
|
||||
let (contents, index) = notebook.index();
|
||||
assert_eq!(
|
||||
contents,
|
||||
r#"def unused_variable():
|
||||
x = 1
|
||||
y = 2
|
||||
print(f"cell one: {y}")
|
||||
|
||||
unused_variable()
|
||||
def mutable_argument(z=set()):
|
||||
print(f"cell two: {z}")
|
||||
|
||||
mutable_argument()
|
||||
"#
|
||||
);
|
||||
assert_eq!(
|
||||
index,
|
||||
JupyterIndex {
|
||||
row_to_cell: vec![0, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3],
|
||||
row_to_row_in_cell: vec![0, 1, 2, 3, 4, 5, 6, 1, 2, 3, 4],
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
256
crates/ruff/src/jupyter/schema.rs
Normal file
256
crates/ruff/src/jupyter/schema.rs
Normal file
@@ -0,0 +1,256 @@
|
||||
//! The JSON schema of a Jupyter Notebook, entrypoint is [`JupyterNotebook`]
|
||||
//!
|
||||
//! Generated by <https://app.quicktype.io/> from
|
||||
//! <https://github.com/jupyter/nbformat/blob/16b53251aabf472ad9406ddb1f78b0421c014eeb/nbformat/v4/nbformat.v4.schema.json>
|
||||
//! Jupyter Notebook v4.5 JSON schema.
|
||||
//!
|
||||
//! The following changes were made to the generated version: `Cell::id` is optional because it
|
||||
//! wasn't required <v4.5, `#[serde(deny_unknown_fields)]` was added where the schema had
|
||||
//! `"additionalProperties": false` and `#[serde(flatten)] pub other: BTreeMap<String, Value>`
|
||||
//! for `"additionalProperties": true` as preparation for round-trip support.
|
||||
|
||||
use std::collections::{BTreeMap, HashMap};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::Value;
|
||||
|
||||
/// The root of the JSON of a Jupyter Notebook
|
||||
///
|
||||
/// Generated by <https://app.quicktype.io/> from
|
||||
/// <https://github.com/jupyter/nbformat/blob/16b53251aabf472ad9406ddb1f78b0421c014eeb/nbformat/v4/nbformat.v4.schema.json>
|
||||
/// Jupyter Notebook v4.5 JSON schema.
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct JupyterNotebook {
|
||||
/// Array of cells of the current notebook.
|
||||
pub cells: Vec<Cell>,
|
||||
/// Notebook root-level metadata.
|
||||
pub metadata: JupyterNotebookMetadata,
|
||||
/// Notebook format (major number). Incremented between backwards incompatible changes to the
|
||||
/// notebook format.
|
||||
pub nbformat: i64,
|
||||
/// Notebook format (minor number). Incremented for backward compatible changes to the
|
||||
/// notebook format.
|
||||
pub nbformat_minor: i64,
|
||||
}
|
||||
|
||||
/// Notebook raw nbconvert cell.
|
||||
///
|
||||
/// Notebook markdown cell.
|
||||
///
|
||||
/// Notebook code cell.
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct Cell {
|
||||
pub attachments: Option<HashMap<String, HashMap<String, SourceValue>>>,
|
||||
/// String identifying the type of cell.
|
||||
pub cell_type: CellType,
|
||||
/// Technically, id isn't required (it's not even present) in schema v4.0 through v4.4, but
|
||||
/// it's required in v4.5. Main issue is that pycharm creates notebooks without an id
|
||||
/// <https://youtrack.jetbrains.com/issue/PY-59438/Jupyter-notebooks-created-with-PyCharm-are-missing-the-id-field-in-cells-in-the-.ipynb-json>
|
||||
pub id: Option<String>,
|
||||
/// Cell-level metadata.
|
||||
pub metadata: CellMetadata,
|
||||
pub source: SourceValue,
|
||||
/// The code cell's prompt number. Will be null if the cell has not been run.
|
||||
pub execution_count: Option<i64>,
|
||||
/// Execution, display, or stream outputs.
|
||||
pub outputs: Option<Vec<Output>>,
|
||||
}
|
||||
|
||||
/// Cell-level metadata.
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct CellMetadata {
|
||||
/// Raw cell metadata format for nbconvert.
|
||||
pub format: Option<String>,
|
||||
/// Official Jupyter Metadata for Raw Cells
|
||||
///
|
||||
/// Official Jupyter Metadata for Markdown Cells
|
||||
///
|
||||
/// Official Jupyter Metadata for Code Cells
|
||||
pub jupyter: Option<HashMap<String, Option<Value>>>,
|
||||
pub name: Option<String>,
|
||||
pub tags: Option<Vec<String>>,
|
||||
/// Whether the cell's output is collapsed/expanded.
|
||||
pub collapsed: Option<bool>,
|
||||
/// Execution time for the code in the cell. This tracks time at which messages are received
|
||||
/// from iopub or shell channels
|
||||
pub execution: Option<Execution>,
|
||||
/// Whether the cell's output is scrolled, unscrolled, or autoscrolled.
|
||||
pub scrolled: Option<ScrolledUnion>,
|
||||
/// Custom added: round-trip support
|
||||
#[serde(flatten)]
|
||||
pub other: BTreeMap<String, Value>,
|
||||
}
|
||||
|
||||
/// Execution time for the code in the cell. This tracks time at which messages are received
|
||||
/// from iopub or shell channels
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct Execution {
|
||||
/// header.date (in ISO 8601 format) of iopub channel's execute_input message. It indicates
|
||||
/// the time at which the kernel broadcasts an execute_input message to connected frontends
|
||||
#[serde(rename = "iopub.execute_input")]
|
||||
pub iopub_execute_input: Option<String>,
|
||||
/// header.date (in ISO 8601 format) of iopub channel's kernel status message when the status
|
||||
/// is 'busy'
|
||||
#[serde(rename = "iopub.status.busy")]
|
||||
pub iopub_status_busy: Option<String>,
|
||||
/// header.date (in ISO 8601 format) of iopub channel's kernel status message when the status
|
||||
/// is 'idle'. It indicates the time at which kernel finished processing the associated
|
||||
/// request
|
||||
#[serde(rename = "iopub.status.idle")]
|
||||
pub iopub_status_idle: Option<String>,
|
||||
/// header.date (in ISO 8601 format) of the shell channel's execute_reply message. It
|
||||
/// indicates the time at which the execute_reply message was created
|
||||
#[serde(rename = "shell.execute_reply")]
|
||||
pub shell_execute_reply: Option<String>,
|
||||
}
|
||||
|
||||
/// Result of executing a code cell.
|
||||
///
|
||||
/// Data displayed as a result of code cell execution.
|
||||
///
|
||||
/// Stream output from a code cell.
|
||||
///
|
||||
/// Output of an error that occurred during code cell execution.
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct Output {
|
||||
pub data: Option<HashMap<String, SourceValue>>,
|
||||
/// A result's prompt number.
|
||||
pub execution_count: Option<i64>,
|
||||
pub metadata: Option<HashMap<String, Option<Value>>>,
|
||||
/// Type of cell output.
|
||||
pub output_type: OutputType,
|
||||
/// The name of the stream (stdout, stderr).
|
||||
pub name: Option<String>,
|
||||
/// The stream's text output, represented as an array of strings.
|
||||
pub text: Option<TextUnion>,
|
||||
/// The name of the error.
|
||||
pub ename: Option<String>,
|
||||
/// The value, or message, of the error.
|
||||
pub evalue: Option<String>,
|
||||
/// The error's traceback, represented as an array of strings.
|
||||
pub traceback: Option<Vec<String>>,
|
||||
}
|
||||
|
||||
/// Notebook root-level metadata.
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct JupyterNotebookMetadata {
|
||||
/// The author(s) of the notebook document
|
||||
pub authors: Option<Vec<Option<Value>>>,
|
||||
/// Kernel information.
|
||||
pub kernelspec: Option<Kernelspec>,
|
||||
/// Kernel information.
|
||||
pub language_info: Option<LanguageInfo>,
|
||||
/// Original notebook format (major number) before converting the notebook between versions.
|
||||
/// This should never be written to a file.
|
||||
pub orig_nbformat: Option<i64>,
|
||||
/// The title of the notebook document
|
||||
pub title: Option<String>,
|
||||
/// Custom added: round-trip support
|
||||
#[serde(flatten)]
|
||||
pub other: BTreeMap<String, Value>,
|
||||
}
|
||||
|
||||
/// Kernel information.
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct Kernelspec {
|
||||
/// Name to display in UI.
|
||||
pub display_name: String,
|
||||
/// Name of the kernel specification.
|
||||
pub name: String,
|
||||
/// Custom added: round-trip support
|
||||
#[serde(flatten)]
|
||||
pub other: BTreeMap<String, Value>,
|
||||
}
|
||||
|
||||
/// Kernel information.
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct LanguageInfo {
|
||||
/// The codemirror mode to use for code in this language.
|
||||
pub codemirror_mode: Option<CodemirrorMode>,
|
||||
/// The file extension for files in this language.
|
||||
pub file_extension: Option<String>,
|
||||
/// The mimetype corresponding to files in this language.
|
||||
pub mimetype: Option<String>,
|
||||
/// The programming language which this kernel runs.
|
||||
pub name: String,
|
||||
/// The pygments lexer to use for code in this language.
|
||||
pub pygments_lexer: Option<String>,
|
||||
/// Custom added: round-trip support
|
||||
#[serde(flatten)]
|
||||
pub other: BTreeMap<String, Value>,
|
||||
}
|
||||
|
||||
/// mimetype output (e.g. text/plain), represented as either an array of strings or a
|
||||
/// string.
|
||||
///
|
||||
/// Contents of the cell, represented as an array of lines.
|
||||
///
|
||||
/// The stream's text output, represented as an array of strings.
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum SourceValue {
|
||||
String(String),
|
||||
StringArray(Vec<String>),
|
||||
}
|
||||
|
||||
/// Whether the cell's output is scrolled, unscrolled, or autoscrolled.
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum ScrolledUnion {
|
||||
Bool(bool),
|
||||
Enum(ScrolledEnum),
|
||||
}
|
||||
|
||||
/// mimetype output (e.g. text/plain), represented as either an array of strings or a
|
||||
/// string.
|
||||
///
|
||||
/// Contents of the cell, represented as an array of lines.
|
||||
///
|
||||
/// The stream's text output, represented as an array of strings.
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum TextUnion {
|
||||
String(String),
|
||||
StringArray(Vec<String>),
|
||||
}
|
||||
|
||||
/// The codemirror mode to use for code in this language.
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum CodemirrorMode {
|
||||
AnythingMap(HashMap<String, Option<Value>>),
|
||||
String(String),
|
||||
}
|
||||
|
||||
/// String identifying the type of cell.
|
||||
#[derive(Debug, Serialize, Deserialize, PartialEq)]
|
||||
pub enum CellType {
|
||||
#[serde(rename = "code")]
|
||||
Code,
|
||||
#[serde(rename = "markdown")]
|
||||
Markdown,
|
||||
#[serde(rename = "raw")]
|
||||
Raw,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub enum ScrolledEnum {
|
||||
#[serde(rename = "auto")]
|
||||
Auto,
|
||||
}
|
||||
|
||||
/// Type of cell output.
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub enum OutputType {
|
||||
#[serde(rename = "display_data")]
|
||||
DisplayData,
|
||||
#[serde(rename = "error")]
|
||||
Error,
|
||||
#[serde(rename = "execute_result")]
|
||||
ExecuteResult,
|
||||
#[serde(rename = "stream")]
|
||||
Stream,
|
||||
}
|
||||
@@ -20,6 +20,7 @@ mod docstrings;
|
||||
pub mod fix;
|
||||
pub mod flake8_to_ruff;
|
||||
pub mod fs;
|
||||
pub mod jupyter;
|
||||
mod lex;
|
||||
pub mod linter;
|
||||
pub mod logging;
|
||||
|
||||
@@ -204,7 +204,7 @@ pub fn check_path(
|
||||
if !diagnostics.is_empty() && !settings.per_file_ignores.is_empty() {
|
||||
let ignores = fs::ignores_from_path(path, &settings.per_file_ignores);
|
||||
if !ignores.is_empty() {
|
||||
diagnostics.retain(|diagnostic| !ignores.contains(&diagnostic.kind.rule()));
|
||||
diagnostics.retain(|diagnostic| !ignores.contains(diagnostic.kind.rule()));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ use log::warn;
|
||||
use nohash_hasher::IntMap;
|
||||
use once_cell::sync::Lazy;
|
||||
use regex::Regex;
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
use rustc_hash::FxHashMap;
|
||||
use rustpython_parser::ast::Location;
|
||||
|
||||
use ruff_diagnostics::Diagnostic;
|
||||
@@ -17,7 +17,7 @@ use ruff_python_ast::source_code::{LineEnding, Locator};
|
||||
use ruff_python_ast::types::Range;
|
||||
|
||||
use crate::codes::NoqaCode;
|
||||
use crate::registry::{AsRule, Rule};
|
||||
use crate::registry::{AsRule, Rule, RuleSet};
|
||||
use crate::rule_redirects::get_redirect_target;
|
||||
|
||||
static NOQA_LINE_REGEX: Lazy<Regex> = Lazy::new(|| {
|
||||
@@ -28,49 +28,6 @@ static NOQA_LINE_REGEX: Lazy<Regex> = Lazy::new(|| {
|
||||
});
|
||||
static SPLIT_COMMA_REGEX: Lazy<Regex> = Lazy::new(|| Regex::new(r"[,\s]").unwrap());
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Exemption<'a> {
|
||||
None,
|
||||
All,
|
||||
Codes(Vec<&'a str>),
|
||||
}
|
||||
|
||||
/// Return `true` if a file is exempt from checking based on the contents of the
|
||||
/// given line.
|
||||
pub fn extract_file_exemption(line: &str) -> Exemption {
|
||||
let line = line.trim_start();
|
||||
|
||||
if line.starts_with("# flake8: noqa")
|
||||
|| line.starts_with("# flake8: NOQA")
|
||||
|| line.starts_with("# flake8: NoQA")
|
||||
{
|
||||
return Exemption::All;
|
||||
}
|
||||
|
||||
if let Some(remainder) = line
|
||||
.strip_prefix("# ruff: noqa")
|
||||
.or_else(|| line.strip_prefix("# ruff: NOQA"))
|
||||
.or_else(|| line.strip_prefix("# ruff: NoQA"))
|
||||
{
|
||||
if remainder.is_empty() {
|
||||
return Exemption::All;
|
||||
} else if let Some(codes) = remainder.strip_prefix(':') {
|
||||
let codes: Vec<&str> = SPLIT_COMMA_REGEX
|
||||
.split(codes.trim())
|
||||
.map(str::trim)
|
||||
.filter(|code| !code.is_empty())
|
||||
.collect();
|
||||
if codes.is_empty() {
|
||||
warn!("Expected rule codes on `noqa` directive: \"{line}\"");
|
||||
}
|
||||
return Exemption::Codes(codes);
|
||||
}
|
||||
warn!("Unexpected suffix on `noqa` directive: \"{line}\"");
|
||||
}
|
||||
|
||||
Exemption::None
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Directive<'a> {
|
||||
None,
|
||||
@@ -119,6 +76,47 @@ pub fn extract_noqa_directive(line: &str) -> Directive {
|
||||
}
|
||||
}
|
||||
|
||||
enum ParsedExemption<'a> {
|
||||
None,
|
||||
All,
|
||||
Codes(Vec<&'a str>),
|
||||
}
|
||||
|
||||
/// Return a [`ParsedExemption`] for a given comment line.
|
||||
fn parse_file_exemption(line: &str) -> ParsedExemption {
|
||||
let line = line.trim_start();
|
||||
|
||||
if line.starts_with("# flake8: noqa")
|
||||
|| line.starts_with("# flake8: NOQA")
|
||||
|| line.starts_with("# flake8: NoQA")
|
||||
{
|
||||
return ParsedExemption::All;
|
||||
}
|
||||
|
||||
if let Some(remainder) = line
|
||||
.strip_prefix("# ruff: noqa")
|
||||
.or_else(|| line.strip_prefix("# ruff: NOQA"))
|
||||
.or_else(|| line.strip_prefix("# ruff: NoQA"))
|
||||
{
|
||||
if remainder.is_empty() {
|
||||
return ParsedExemption::All;
|
||||
} else if let Some(codes) = remainder.strip_prefix(':') {
|
||||
let codes: Vec<&str> = SPLIT_COMMA_REGEX
|
||||
.split(codes.trim())
|
||||
.map(str::trim)
|
||||
.filter(|code| !code.is_empty())
|
||||
.collect();
|
||||
if codes.is_empty() {
|
||||
warn!("Expected rule codes on `noqa` directive: \"{line}\"");
|
||||
}
|
||||
return ParsedExemption::Codes(codes);
|
||||
}
|
||||
warn!("Unexpected suffix on `noqa` directive: \"{line}\"");
|
||||
}
|
||||
|
||||
ParsedExemption::None
|
||||
}
|
||||
|
||||
/// Returns `true` if the string list of `codes` includes `code` (or an alias
|
||||
/// thereof).
|
||||
pub fn includes(needle: Rule, haystack: &[&str]) -> bool {
|
||||
@@ -147,6 +145,43 @@ pub fn rule_is_ignored(
|
||||
}
|
||||
}
|
||||
|
||||
pub enum FileExemption {
|
||||
None,
|
||||
All,
|
||||
Codes(Vec<NoqaCode>),
|
||||
}
|
||||
|
||||
/// Extract the [`FileExemption`] for a given Python source file, enumerating any rules that are
|
||||
/// globally ignored within the file.
|
||||
pub fn file_exemption(lines: &[&str], commented_lines: &[usize]) -> FileExemption {
|
||||
let mut exempt_codes: Vec<NoqaCode> = vec![];
|
||||
|
||||
for lineno in commented_lines {
|
||||
match parse_file_exemption(lines[lineno - 1]) {
|
||||
ParsedExemption::All => {
|
||||
return FileExemption::All;
|
||||
}
|
||||
ParsedExemption::Codes(codes) => {
|
||||
exempt_codes.extend(codes.into_iter().filter_map(|code| {
|
||||
if let Ok(rule) = Rule::from_code(get_redirect_target(code).unwrap_or(code)) {
|
||||
Some(rule.noqa_code())
|
||||
} else {
|
||||
warn!("Invalid code provided to `# ruff: noqa`: {}", code);
|
||||
None
|
||||
}
|
||||
}));
|
||||
}
|
||||
ParsedExemption::None => {}
|
||||
}
|
||||
}
|
||||
|
||||
if exempt_codes.is_empty() {
|
||||
FileExemption::None
|
||||
} else {
|
||||
FileExemption::Codes(exempt_codes)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_noqa(
|
||||
path: &Path,
|
||||
diagnostics: &[Diagnostic],
|
||||
@@ -174,46 +209,28 @@ fn add_noqa_inner(
|
||||
line_ending: &LineEnding,
|
||||
) -> (usize, String) {
|
||||
// Map of line number to set of (non-ignored) diagnostic codes that are triggered on that line.
|
||||
let mut matches_by_line: FxHashMap<usize, FxHashSet<Rule>> = FxHashMap::default();
|
||||
|
||||
// Whether the file is exempted from all checks.
|
||||
let mut file_exempted = false;
|
||||
|
||||
// Codes that are globally exempted (within the current file).
|
||||
let mut file_exemptions: Vec<NoqaCode> = vec![];
|
||||
let mut matches_by_line: FxHashMap<usize, RuleSet> = FxHashMap::default();
|
||||
|
||||
let lines: Vec<&str> = contents.universal_newlines().collect();
|
||||
for lineno in commented_lines {
|
||||
match extract_file_exemption(lines[lineno - 1]) {
|
||||
Exemption::All => {
|
||||
file_exempted = true;
|
||||
}
|
||||
Exemption::Codes(codes) => {
|
||||
file_exemptions.extend(codes.into_iter().filter_map(|code| {
|
||||
if let Ok(rule) = Rule::from_code(get_redirect_target(code).unwrap_or(code)) {
|
||||
Some(rule.noqa_code())
|
||||
} else {
|
||||
warn!("Invalid code provided to `# ruff: noqa`: {}", code);
|
||||
None
|
||||
}
|
||||
}));
|
||||
}
|
||||
Exemption::None => {}
|
||||
}
|
||||
}
|
||||
|
||||
// Whether the file is exempted from all checks.
|
||||
// Codes that are globally exempted (within the current file).
|
||||
let exemption = file_exemption(&lines, commented_lines);
|
||||
|
||||
// Mark any non-ignored diagnostics.
|
||||
for diagnostic in diagnostics {
|
||||
// If the file is exempted, don't add any noqa directives.
|
||||
if file_exempted {
|
||||
continue;
|
||||
}
|
||||
|
||||
// If the diagnostic is ignored by a global exemption, don't add a noqa directive.
|
||||
if !file_exemptions.is_empty() {
|
||||
if file_exemptions.contains(&diagnostic.kind.rule().noqa_code()) {
|
||||
match &exemption {
|
||||
FileExemption::All => {
|
||||
// If the file is exempted, don't add any noqa directives.
|
||||
continue;
|
||||
}
|
||||
FileExemption::Codes(codes) => {
|
||||
// If the diagnostic is ignored by a global exemption, don't add a noqa directive.
|
||||
if codes.contains(&diagnostic.kind.rule().noqa_code()) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
FileExemption::None => {}
|
||||
}
|
||||
|
||||
// Is the violation ignored by a `noqa` directive on the parent line?
|
||||
@@ -280,7 +297,7 @@ fn add_noqa_inner(
|
||||
output.push_str(" # noqa: ");
|
||||
|
||||
// Add codes.
|
||||
push_codes(&mut output, rules.iter().map(Rule::noqa_code));
|
||||
push_codes(&mut output, rules.iter().map(|rule| rule.noqa_code()));
|
||||
output.push_str(line_ending);
|
||||
count += 1;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
//! Registry of all [`Rule`] implementations.
|
||||
|
||||
mod rule_set;
|
||||
|
||||
use strum_macros::{AsRefStr, EnumIter};
|
||||
|
||||
use ruff_diagnostics::Violation;
|
||||
@@ -7,71 +9,72 @@ use ruff_macros::RuleNamespace;
|
||||
|
||||
use crate::codes::{self, RuleCodePrefix};
|
||||
use crate::rules;
|
||||
pub use rule_set::{RuleSet, RuleSetIterator};
|
||||
|
||||
ruff_macros::register_rules!(
|
||||
// pycodestyle errors
|
||||
rules::pycodestyle::rules::MixedSpacesAndTabs,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
rules::pycodestyle::rules::IndentationWithInvalidMultiple,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
rules::pycodestyle::rules::NoIndentedBlock,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
rules::pycodestyle::rules::UnexpectedIndentation,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
rules::pycodestyle::rules::IndentationWithInvalidMultipleComment,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
rules::pycodestyle::rules::NoIndentedBlockComment,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
rules::pycodestyle::rules::UnexpectedIndentationComment,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
rules::pycodestyle::rules::OverIndented,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
rules::pycodestyle::rules::WhitespaceAfterOpenBracket,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
rules::pycodestyle::rules::WhitespaceBeforeCloseBracket,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
rules::pycodestyle::rules::WhitespaceBeforePunctuation,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
rules::pycodestyle::rules::MultipleSpacesBeforeOperator,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
rules::pycodestyle::rules::MultipleSpacesAfterOperator,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
rules::pycodestyle::rules::TabBeforeOperator,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
rules::pycodestyle::rules::TabAfterOperator,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
rules::pycodestyle::rules::TooFewSpacesBeforeInlineComment,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
rules::pycodestyle::rules::NoSpaceAfterInlineComment,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
rules::pycodestyle::rules::NoSpaceAfterBlockComment,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
rules::pycodestyle::rules::MultipleLeadingHashesForBlockComment,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
rules::pycodestyle::rules::MultipleSpacesAfterKeyword,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
rules::pycodestyle::rules::MissingWhitespace,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
rules::pycodestyle::rules::MissingWhitespaceAfterKeyword,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
rules::pycodestyle::rules::MultipleSpacesBeforeKeyword,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
rules::pycodestyle::rules::MissingWhitespaceAroundOperator,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
rules::pycodestyle::rules::MissingWhitespaceAroundArithmeticOperator,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
rules::pycodestyle::rules::MissingWhitespaceAroundBitwiseOrShiftOperator,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
rules::pycodestyle::rules::MissingWhitespaceAroundModuloOperator,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
rules::pycodestyle::rules::TabAfterKeyword,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
rules::pycodestyle::rules::UnexpectedSpacesAroundKeywordParameterEquals,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
rules::pycodestyle::rules::MissingWhitespaceAroundParameterEquals,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
rules::pycodestyle::rules::WhitespaceBeforeParameters,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
rules::pycodestyle::rules::TabBeforeKeyword,
|
||||
rules::pycodestyle::rules::MultipleImportsOnOneLine,
|
||||
rules::pycodestyle::rules::ModuleImportNotAtTopOfFile,
|
||||
@@ -92,19 +95,19 @@ ruff_macros::register_rules!(
|
||||
rules::pycodestyle::rules::IOError,
|
||||
rules::pycodestyle::rules::SyntaxError,
|
||||
// pycodestyle warnings
|
||||
rules::pycodestyle::rules::IndentationContainsTabs,
|
||||
rules::pycodestyle::rules::TabIndentation,
|
||||
rules::pycodestyle::rules::TrailingWhitespace,
|
||||
rules::pycodestyle::rules::NoNewLineAtEndOfFile,
|
||||
rules::pycodestyle::rules::BlankLineContainsWhitespace,
|
||||
rules::pycodestyle::rules::MissingNewlineAtEndOfFile,
|
||||
rules::pycodestyle::rules::BlankLineWithWhitespace,
|
||||
rules::pycodestyle::rules::DocLineTooLong,
|
||||
rules::pycodestyle::rules::InvalidEscapeSequence,
|
||||
// pyflakes
|
||||
rules::pyflakes::rules::UnusedImport,
|
||||
rules::pyflakes::rules::ImportShadowedByLoopVar,
|
||||
rules::pyflakes::rules::ImportStar,
|
||||
rules::pyflakes::rules::UndefinedLocalWithImportStar,
|
||||
rules::pyflakes::rules::LateFutureImport,
|
||||
rules::pyflakes::rules::ImportStarUsage,
|
||||
rules::pyflakes::rules::ImportStarNotPermitted,
|
||||
rules::pyflakes::rules::UndefinedLocalWithImportStarUsage,
|
||||
rules::pyflakes::rules::UndefinedLocalWithNestedImportStarUsage,
|
||||
rules::pyflakes::rules::FutureFeatureNotDefined,
|
||||
rules::pyflakes::rules::PercentFormatInvalidFormat,
|
||||
rules::pyflakes::rules::PercentFormatExpectedMapping,
|
||||
@@ -124,7 +127,7 @@ ruff_macros::register_rules!(
|
||||
rules::pyflakes::rules::MultiValueRepeatedKeyLiteral,
|
||||
rules::pyflakes::rules::MultiValueRepeatedKeyVariable,
|
||||
rules::pyflakes::rules::ExpressionsInStarAssignment,
|
||||
rules::pyflakes::rules::TwoStarredExpressions,
|
||||
rules::pyflakes::rules::MultipleStarredExpressions,
|
||||
rules::pyflakes::rules::AssertTuple,
|
||||
rules::pyflakes::rules::IsLiteral,
|
||||
rules::pyflakes::rules::InvalidPrintSyntax,
|
||||
@@ -143,6 +146,8 @@ ruff_macros::register_rules!(
|
||||
rules::pyflakes::rules::UnusedAnnotation,
|
||||
rules::pyflakes::rules::RaiseNotImplemented,
|
||||
// pylint
|
||||
rules::pylint::rules::AssertOnStringLiteral,
|
||||
rules::pylint::rules::UselessReturn,
|
||||
rules::pylint::rules::YieldInInit,
|
||||
rules::pylint::rules::InvalidAllObject,
|
||||
rules::pylint::rules::InvalidAllFormat,
|
||||
@@ -150,6 +155,7 @@ ruff_macros::register_rules!(
|
||||
rules::pylint::rules::InvalidEnvvarValue,
|
||||
rules::pylint::rules::BadStringFormatType,
|
||||
rules::pylint::rules::BidirectionalUnicode,
|
||||
rules::pylint::rules::BinaryOpException,
|
||||
rules::pylint::rules::InvalidCharacterBackspace,
|
||||
rules::pylint::rules::InvalidCharacterSub,
|
||||
rules::pylint::rules::InvalidCharacterEsc,
|
||||
@@ -161,15 +167,15 @@ ruff_macros::register_rules!(
|
||||
rules::pylint::rules::UselessImportAlias,
|
||||
rules::pylint::rules::UnnecessaryDirectLambdaCall,
|
||||
rules::pylint::rules::NonlocalWithoutBinding,
|
||||
rules::pylint::rules::UsedPriorGlobalDeclaration,
|
||||
rules::pylint::rules::LoadBeforeGlobalDeclaration,
|
||||
rules::pylint::rules::AwaitOutsideAsync,
|
||||
rules::pylint::rules::PropertyWithParameters,
|
||||
rules::pylint::rules::ReturnInInit,
|
||||
rules::pylint::rules::ConsiderUsingFromImport,
|
||||
rules::pylint::rules::ManualFromImport,
|
||||
rules::pylint::rules::CompareToEmptyString,
|
||||
rules::pylint::rules::ComparisonOfConstant,
|
||||
rules::pylint::rules::ConsiderMergingIsinstance,
|
||||
rules::pylint::rules::ConsiderUsingSysExit,
|
||||
rules::pylint::rules::RepeatedIsinstanceCalls,
|
||||
rules::pylint::rules::SysExitAlias,
|
||||
rules::pylint::rules::MagicValueComparison,
|
||||
rules::pylint::rules::UselessElseOnLoop,
|
||||
rules::pylint::rules::GlobalStatement,
|
||||
@@ -193,7 +199,7 @@ ruff_macros::register_rules!(
|
||||
rules::flake8_bugbear::rules::MutableArgumentDefault,
|
||||
rules::flake8_bugbear::rules::NoExplicitStacklevel,
|
||||
rules::flake8_bugbear::rules::UnusedLoopControlVariable,
|
||||
rules::flake8_bugbear::rules::FunctionCallArgumentDefault,
|
||||
rules::flake8_bugbear::rules::FunctionCallInDefaultArgument,
|
||||
rules::flake8_bugbear::rules::GetAttrWithConstant,
|
||||
rules::flake8_bugbear::rules::SetAttrWithConstant,
|
||||
rules::flake8_bugbear::rules::AssertFalse,
|
||||
@@ -258,8 +264,8 @@ ruff_macros::register_rules!(
|
||||
rules::flake8_implicit_str_concat::rules::MultiLineImplicitStringConcatenation,
|
||||
rules::flake8_implicit_str_concat::rules::ExplicitStringConcatenation,
|
||||
// flake8-print
|
||||
rules::flake8_print::rules::PrintFound,
|
||||
rules::flake8_print::rules::PPrintFound,
|
||||
rules::flake8_print::rules::Print,
|
||||
rules::flake8_print::rules::PPrint,
|
||||
// flake8-quotes
|
||||
rules::flake8_quotes::rules::BadQuotesInlineString,
|
||||
rules::flake8_quotes::rules::BadQuotesMultilineString,
|
||||
@@ -271,38 +277,38 @@ ruff_macros::register_rules!(
|
||||
rules::flake8_annotations::rules::MissingTypeKwargs,
|
||||
rules::flake8_annotations::rules::MissingTypeSelf,
|
||||
rules::flake8_annotations::rules::MissingTypeCls,
|
||||
rules::flake8_annotations::rules::MissingReturnTypePublicFunction,
|
||||
rules::flake8_annotations::rules::MissingReturnTypeUndocumentedPublicFunction,
|
||||
rules::flake8_annotations::rules::MissingReturnTypePrivateFunction,
|
||||
rules::flake8_annotations::rules::MissingReturnTypeSpecialMethod,
|
||||
rules::flake8_annotations::rules::MissingReturnTypeStaticMethod,
|
||||
rules::flake8_annotations::rules::MissingReturnTypeClassMethod,
|
||||
rules::flake8_annotations::rules::AnyType,
|
||||
// flake8-2020
|
||||
rules::flake8_2020::rules::SysVersionSlice3Referenced,
|
||||
rules::flake8_2020::rules::SysVersion2Referenced,
|
||||
rules::flake8_2020::rules::SysVersionSlice3,
|
||||
rules::flake8_2020::rules::SysVersion2,
|
||||
rules::flake8_2020::rules::SysVersionCmpStr3,
|
||||
rules::flake8_2020::rules::SysVersionInfo0Eq3Referenced,
|
||||
rules::flake8_2020::rules::SixPY3Referenced,
|
||||
rules::flake8_2020::rules::SysVersionInfo0Eq3,
|
||||
rules::flake8_2020::rules::SixPY3,
|
||||
rules::flake8_2020::rules::SysVersionInfo1CmpInt,
|
||||
rules::flake8_2020::rules::SysVersionInfoMinorCmpInt,
|
||||
rules::flake8_2020::rules::SysVersion0Referenced,
|
||||
rules::flake8_2020::rules::SysVersion0,
|
||||
rules::flake8_2020::rules::SysVersionCmpStr10,
|
||||
rules::flake8_2020::rules::SysVersionSlice1Referenced,
|
||||
rules::flake8_2020::rules::SysVersionSlice1,
|
||||
// flake8-simplify
|
||||
rules::flake8_simplify::rules::ManualDictLookup,
|
||||
rules::flake8_simplify::rules::IfElseBlockInsteadOfDictLookup,
|
||||
rules::flake8_simplify::rules::DuplicateIsinstanceCall,
|
||||
rules::flake8_simplify::rules::CollapsibleIf,
|
||||
rules::flake8_simplify::rules::NeedlessBool,
|
||||
rules::flake8_simplify::rules::UseContextlibSuppress,
|
||||
rules::flake8_simplify::rules::SuppressibleException,
|
||||
rules::flake8_simplify::rules::ReturnInTryExceptFinally,
|
||||
rules::flake8_simplify::rules::UseTernaryOperator,
|
||||
rules::flake8_simplify::rules::IfElseBlockInsteadOfIfExp,
|
||||
rules::flake8_simplify::rules::CompareWithTuple,
|
||||
rules::flake8_simplify::rules::ReimplementedBuiltin,
|
||||
rules::flake8_simplify::rules::UseCapitalEnvironmentVariables,
|
||||
rules::flake8_simplify::rules::UncapitalizedEnvironmentVariables,
|
||||
rules::flake8_simplify::rules::IfWithSameArms,
|
||||
rules::flake8_simplify::rules::OpenFileWithContextHandler,
|
||||
rules::flake8_simplify::rules::MultipleWithStatements,
|
||||
rules::flake8_simplify::rules::KeyInDict,
|
||||
rules::flake8_simplify::rules::InDictKeys,
|
||||
rules::flake8_simplify::rules::NegateEqualOp,
|
||||
rules::flake8_simplify::rules::NegateNotEqualOp,
|
||||
rules::flake8_simplify::rules::DoubleNegation,
|
||||
@@ -314,14 +320,14 @@ ruff_macros::register_rules!(
|
||||
rules::flake8_simplify::rules::ExprOrTrue,
|
||||
rules::flake8_simplify::rules::ExprAndFalse,
|
||||
rules::flake8_simplify::rules::YodaConditions,
|
||||
rules::flake8_simplify::rules::DictGetWithDefault,
|
||||
rules::flake8_simplify::rules::IfElseBlockInsteadOfDictGet,
|
||||
// pyupgrade
|
||||
rules::pyupgrade::rules::UselessMetaclassType,
|
||||
rules::pyupgrade::rules::TypeOfPrimitive,
|
||||
rules::pyupgrade::rules::UselessObjectInheritance,
|
||||
rules::pyupgrade::rules::DeprecatedUnittestAlias,
|
||||
rules::pyupgrade::rules::DeprecatedCollectionType,
|
||||
rules::pyupgrade::rules::TypingUnion,
|
||||
rules::pyupgrade::rules::NonPEP585Annotation,
|
||||
rules::pyupgrade::rules::NonPEP604Annotation,
|
||||
rules::pyupgrade::rules::SuperCallWithParameters,
|
||||
rules::pyupgrade::rules::UTF8EncodingDeclaration,
|
||||
rules::pyupgrade::rules::UnnecessaryFutureImport,
|
||||
@@ -336,31 +342,31 @@ ruff_macros::register_rules!(
|
||||
rules::pyupgrade::rules::OpenAlias,
|
||||
rules::pyupgrade::rules::ReplaceUniversalNewlines,
|
||||
rules::pyupgrade::rules::ReplaceStdoutStderr,
|
||||
rules::pyupgrade::rules::RewriteCElementTree,
|
||||
rules::pyupgrade::rules::DeprecatedCElementTree,
|
||||
rules::pyupgrade::rules::OSErrorAlias,
|
||||
rules::pyupgrade::rules::RewriteUnicodeLiteral,
|
||||
rules::pyupgrade::rules::RewriteMockImport,
|
||||
rules::pyupgrade::rules::RewriteListComprehension,
|
||||
rules::pyupgrade::rules::RewriteYieldFrom,
|
||||
rules::pyupgrade::rules::UnicodeKindPrefix,
|
||||
rules::pyupgrade::rules::DeprecatedMockImport,
|
||||
rules::pyupgrade::rules::UnpackedListComprehension,
|
||||
rules::pyupgrade::rules::YieldInForLoop,
|
||||
rules::pyupgrade::rules::UnnecessaryBuiltinImport,
|
||||
rules::pyupgrade::rules::FormatLiterals,
|
||||
rules::pyupgrade::rules::PrintfStringFormatting,
|
||||
rules::pyupgrade::rules::FString,
|
||||
rules::pyupgrade::rules::FunctoolsCache,
|
||||
rules::pyupgrade::rules::LRUCacheWithMaxsizeNone,
|
||||
rules::pyupgrade::rules::ExtraneousParentheses,
|
||||
rules::pyupgrade::rules::DeprecatedImport,
|
||||
rules::pyupgrade::rules::OutdatedVersionBlock,
|
||||
rules::pyupgrade::rules::QuotedAnnotation,
|
||||
rules::pyupgrade::rules::IsinstanceWithTuple,
|
||||
rules::pyupgrade::rules::NonPEP604Isinstance,
|
||||
// pydocstyle
|
||||
rules::pydocstyle::rules::PublicModule,
|
||||
rules::pydocstyle::rules::PublicClass,
|
||||
rules::pydocstyle::rules::PublicMethod,
|
||||
rules::pydocstyle::rules::PublicFunction,
|
||||
rules::pydocstyle::rules::PublicPackage,
|
||||
rules::pydocstyle::rules::MagicMethod,
|
||||
rules::pydocstyle::rules::PublicNestedClass,
|
||||
rules::pydocstyle::rules::PublicInit,
|
||||
rules::pydocstyle::rules::UndocumentedPublicModule,
|
||||
rules::pydocstyle::rules::UndocumentedPublicClass,
|
||||
rules::pydocstyle::rules::UndocumentedPublicMethod,
|
||||
rules::pydocstyle::rules::UndocumentedPublicFunction,
|
||||
rules::pydocstyle::rules::UndocumentedPublicPackage,
|
||||
rules::pydocstyle::rules::UndocumentedMagicMethod,
|
||||
rules::pydocstyle::rules::UndocumentedPublicNestedClass,
|
||||
rules::pydocstyle::rules::UndocumentedPublicInit,
|
||||
rules::pydocstyle::rules::FitsOnOneLine,
|
||||
rules::pydocstyle::rules::NoBlankLineBeforeFunction,
|
||||
rules::pydocstyle::rules::NoBlankLineAfterFunction,
|
||||
@@ -368,11 +374,11 @@ ruff_macros::register_rules!(
|
||||
rules::pydocstyle::rules::OneBlankLineAfterClass,
|
||||
rules::pydocstyle::rules::BlankLineAfterSummary,
|
||||
rules::pydocstyle::rules::IndentWithSpaces,
|
||||
rules::pydocstyle::rules::NoUnderIndentation,
|
||||
rules::pydocstyle::rules::NoOverIndentation,
|
||||
rules::pydocstyle::rules::UnderIndentation,
|
||||
rules::pydocstyle::rules::OverIndentation,
|
||||
rules::pydocstyle::rules::NewLineAfterLastParagraph,
|
||||
rules::pydocstyle::rules::NoSurroundingWhitespace,
|
||||
rules::pydocstyle::rules::NoBlankLineBeforeClass,
|
||||
rules::pydocstyle::rules::SurroundingWhitespace,
|
||||
rules::pydocstyle::rules::BlankLineBeforeClass,
|
||||
rules::pydocstyle::rules::MultiLineSummaryFirstLine,
|
||||
rules::pydocstyle::rules::MultiLineSummarySecondLine,
|
||||
rules::pydocstyle::rules::SectionNotOverIndented,
|
||||
@@ -389,9 +395,9 @@ ruff_macros::register_rules!(
|
||||
rules::pydocstyle::rules::DashedUnderlineAfterSection,
|
||||
rules::pydocstyle::rules::SectionUnderlineAfterName,
|
||||
rules::pydocstyle::rules::SectionUnderlineMatchesSectionLength,
|
||||
rules::pydocstyle::rules::BlankLineAfterSection,
|
||||
rules::pydocstyle::rules::BlankLineBeforeSection,
|
||||
rules::pydocstyle::rules::NoBlankLinesBetweenHeaderAndContent,
|
||||
rules::pydocstyle::rules::NoBlankLineAfterSection,
|
||||
rules::pydocstyle::rules::NoBlankLineBeforeSection,
|
||||
rules::pydocstyle::rules::BlankLinesBetweenHeaderAndContent,
|
||||
rules::pydocstyle::rules::BlankLineAfterLastSection,
|
||||
rules::pydocstyle::rules::EmptyDocstringSection,
|
||||
rules::pydocstyle::rules::EndsInPunctuation,
|
||||
@@ -423,24 +429,45 @@ ruff_macros::register_rules!(
|
||||
rules::eradicate::rules::CommentedOutCode,
|
||||
// flake8-bandit
|
||||
rules::flake8_bandit::rules::Assert,
|
||||
rules::flake8_bandit::rules::ExecBuiltin,
|
||||
rules::flake8_bandit::rules::BadFilePermissions,
|
||||
rules::flake8_bandit::rules::ExecBuiltin,
|
||||
rules::flake8_bandit::rules::HardcodedBindAllInterfaces,
|
||||
rules::flake8_bandit::rules::HardcodedPasswordString,
|
||||
rules::flake8_bandit::rules::HardcodedPasswordFuncArg,
|
||||
rules::flake8_bandit::rules::HardcodedPasswordDefault,
|
||||
rules::flake8_bandit::rules::HardcodedPasswordFuncArg,
|
||||
rules::flake8_bandit::rules::HardcodedPasswordString,
|
||||
rules::flake8_bandit::rules::HardcodedSQLExpression,
|
||||
rules::flake8_bandit::rules::HardcodedTempFile,
|
||||
rules::flake8_bandit::rules::TryExceptPass,
|
||||
rules::flake8_bandit::rules::TryExceptContinue,
|
||||
rules::flake8_bandit::rules::RequestWithoutTimeout,
|
||||
rules::flake8_bandit::rules::HashlibInsecureHashFunction,
|
||||
rules::flake8_bandit::rules::Jinja2AutoescapeFalse,
|
||||
rules::flake8_bandit::rules::LoggingConfigInsecureListen,
|
||||
rules::flake8_bandit::rules::RequestWithNoCertValidation,
|
||||
rules::flake8_bandit::rules::UnsafeYAMLLoad,
|
||||
rules::flake8_bandit::rules::RequestWithoutTimeout,
|
||||
rules::flake8_bandit::rules::SnmpInsecureVersion,
|
||||
rules::flake8_bandit::rules::SnmpWeakCryptography,
|
||||
rules::flake8_bandit::rules::LoggingConfigInsecureListen,
|
||||
rules::flake8_bandit::rules::Jinja2AutoescapeFalse,
|
||||
rules::flake8_bandit::rules::SuspiciousEvalUsage,
|
||||
rules::flake8_bandit::rules::SuspiciousFTPLibUsage,
|
||||
rules::flake8_bandit::rules::SuspiciousInsecureCipherUsage,
|
||||
rules::flake8_bandit::rules::SuspiciousInsecureCipherModeUsage,
|
||||
rules::flake8_bandit::rules::SuspiciousInsecureHashUsage,
|
||||
rules::flake8_bandit::rules::SuspiciousMarkSafeUsage,
|
||||
rules::flake8_bandit::rules::SuspiciousMarshalUsage,
|
||||
rules::flake8_bandit::rules::SuspiciousMktempUsage,
|
||||
rules::flake8_bandit::rules::SuspiciousNonCryptographicRandomUsage,
|
||||
rules::flake8_bandit::rules::SuspiciousPickleUsage,
|
||||
rules::flake8_bandit::rules::SuspiciousTelnetUsage,
|
||||
rules::flake8_bandit::rules::SuspiciousURLOpenUsage,
|
||||
rules::flake8_bandit::rules::SuspiciousUnverifiedContextUsage,
|
||||
rules::flake8_bandit::rules::SuspiciousXMLCElementTreeUsage,
|
||||
rules::flake8_bandit::rules::SuspiciousXMLETreeUsage,
|
||||
rules::flake8_bandit::rules::SuspiciousXMLElementTreeUsage,
|
||||
rules::flake8_bandit::rules::SuspiciousXMLExpatBuilderUsage,
|
||||
rules::flake8_bandit::rules::SuspiciousXMLExpatReaderUsage,
|
||||
rules::flake8_bandit::rules::SuspiciousXMLMiniDOMUsage,
|
||||
rules::flake8_bandit::rules::SuspiciousXMLPullDOMUsage,
|
||||
rules::flake8_bandit::rules::SuspiciousXMLSaxUsage,
|
||||
rules::flake8_bandit::rules::TryExceptContinue,
|
||||
rules::flake8_bandit::rules::TryExceptPass,
|
||||
rules::flake8_bandit::rules::UnsafeYAMLLoad,
|
||||
// flake8-boolean-trap
|
||||
rules::flake8_boolean_trap::rules::BooleanPositionalArgInFunctionDefinition,
|
||||
rules::flake8_boolean_trap::rules::BooleanDefaultValueInFunctionDefinition,
|
||||
@@ -464,85 +491,85 @@ ruff_macros::register_rules!(
|
||||
rules::flake8_datetimez::rules::CallDateToday,
|
||||
rules::flake8_datetimez::rules::CallDateFromtimestamp,
|
||||
// pygrep-hooks
|
||||
rules::pygrep_hooks::rules::NoEval,
|
||||
rules::pygrep_hooks::rules::Eval,
|
||||
rules::pygrep_hooks::rules::DeprecatedLogWarn,
|
||||
rules::pygrep_hooks::rules::BlanketTypeIgnore,
|
||||
rules::pygrep_hooks::rules::BlanketNOQA,
|
||||
// pandas-vet
|
||||
rules::pandas_vet::rules::UseOfInplaceArgument,
|
||||
rules::pandas_vet::rules::UseOfDotIsNull,
|
||||
rules::pandas_vet::rules::UseOfDotNotNull,
|
||||
rules::pandas_vet::rules::UseOfDotIx,
|
||||
rules::pandas_vet::rules::UseOfDotAt,
|
||||
rules::pandas_vet::rules::UseOfDotIat,
|
||||
rules::pandas_vet::rules::UseOfDotPivotOrUnstack,
|
||||
rules::pandas_vet::rules::UseOfDotValues,
|
||||
rules::pandas_vet::rules::UseOfDotReadTable,
|
||||
rules::pandas_vet::rules::UseOfDotStack,
|
||||
rules::pandas_vet::rules::UseOfPdMerge,
|
||||
rules::pandas_vet::rules::DfIsABadVariableName,
|
||||
rules::pandas_vet::rules::PandasUseOfInplaceArgument,
|
||||
rules::pandas_vet::rules::PandasUseOfDotIsNull,
|
||||
rules::pandas_vet::rules::PandasUseOfDotNotNull,
|
||||
rules::pandas_vet::rules::PandasUseOfDotIx,
|
||||
rules::pandas_vet::rules::PandasUseOfDotAt,
|
||||
rules::pandas_vet::rules::PandasUseOfDotIat,
|
||||
rules::pandas_vet::rules::PandasUseOfDotPivotOrUnstack,
|
||||
rules::pandas_vet::rules::PandasUseOfDotValues,
|
||||
rules::pandas_vet::rules::PandasUseOfDotReadTable,
|
||||
rules::pandas_vet::rules::PandasUseOfDotStack,
|
||||
rules::pandas_vet::rules::PandasUseOfPdMerge,
|
||||
rules::pandas_vet::rules::PandasDfVariableName,
|
||||
// flake8-errmsg
|
||||
rules::flake8_errmsg::rules::RawStringInException,
|
||||
rules::flake8_errmsg::rules::FStringInException,
|
||||
rules::flake8_errmsg::rules::DotFormatInException,
|
||||
// flake8-pyi
|
||||
rules::flake8_pyi::rules::PrefixTypeParams,
|
||||
rules::flake8_pyi::rules::UnprefixedTypeParam,
|
||||
rules::flake8_pyi::rules::BadVersionInfoComparison,
|
||||
rules::flake8_pyi::rules::UnrecognizedPlatformCheck,
|
||||
rules::flake8_pyi::rules::UnrecognizedPlatformName,
|
||||
rules::flake8_pyi::rules::PassStatementStubBody,
|
||||
rules::flake8_pyi::rules::NonEmptyStubBody,
|
||||
rules::flake8_pyi::rules::DocstringInStub,
|
||||
rules::flake8_pyi::rules::TypedArgumentSimpleDefaults,
|
||||
rules::flake8_pyi::rules::ArgumentSimpleDefaults,
|
||||
rules::flake8_pyi::rules::TypedArgumentDefaultInStub,
|
||||
rules::flake8_pyi::rules::ArgumentDefaultInStub,
|
||||
rules::flake8_pyi::rules::TypeCommentInStub,
|
||||
// flake8-pytest-style
|
||||
rules::flake8_pytest_style::rules::IncorrectFixtureParenthesesStyle,
|
||||
rules::flake8_pytest_style::rules::FixturePositionalArgs,
|
||||
rules::flake8_pytest_style::rules::ExtraneousScopeFunction,
|
||||
rules::flake8_pytest_style::rules::MissingFixtureNameUnderscore,
|
||||
rules::flake8_pytest_style::rules::IncorrectFixtureNameUnderscore,
|
||||
rules::flake8_pytest_style::rules::ParametrizeNamesWrongType,
|
||||
rules::flake8_pytest_style::rules::ParametrizeValuesWrongType,
|
||||
rules::flake8_pytest_style::rules::PatchWithLambda,
|
||||
rules::flake8_pytest_style::rules::UnittestAssertion,
|
||||
rules::flake8_pytest_style::rules::RaisesWithoutException,
|
||||
rules::flake8_pytest_style::rules::RaisesTooBroad,
|
||||
rules::flake8_pytest_style::rules::RaisesWithMultipleStatements,
|
||||
rules::flake8_pytest_style::rules::IncorrectPytestImport,
|
||||
rules::flake8_pytest_style::rules::AssertAlwaysFalse,
|
||||
rules::flake8_pytest_style::rules::FailWithoutMessage,
|
||||
rules::flake8_pytest_style::rules::AssertInExcept,
|
||||
rules::flake8_pytest_style::rules::CompositeAssertion,
|
||||
rules::flake8_pytest_style::rules::FixtureParamWithoutValue,
|
||||
rules::flake8_pytest_style::rules::DeprecatedYieldFixture,
|
||||
rules::flake8_pytest_style::rules::FixtureFinalizerCallback,
|
||||
rules::flake8_pytest_style::rules::UselessYieldFixture,
|
||||
rules::flake8_pytest_style::rules::IncorrectMarkParenthesesStyle,
|
||||
rules::flake8_pytest_style::rules::UnnecessaryAsyncioMarkOnFixture,
|
||||
rules::flake8_pytest_style::rules::ErroneousUseFixturesOnFixture,
|
||||
rules::flake8_pytest_style::rules::UseFixturesWithoutParameters,
|
||||
rules::flake8_pytest_style::rules::PytestFixtureIncorrectParenthesesStyle,
|
||||
rules::flake8_pytest_style::rules::PytestFixturePositionalArgs,
|
||||
rules::flake8_pytest_style::rules::PytestExtraneousScopeFunction,
|
||||
rules::flake8_pytest_style::rules::PytestMissingFixtureNameUnderscore,
|
||||
rules::flake8_pytest_style::rules::PytestIncorrectFixtureNameUnderscore,
|
||||
rules::flake8_pytest_style::rules::PytestParametrizeNamesWrongType,
|
||||
rules::flake8_pytest_style::rules::PytestParametrizeValuesWrongType,
|
||||
rules::flake8_pytest_style::rules::PytestPatchWithLambda,
|
||||
rules::flake8_pytest_style::rules::PytestUnittestAssertion,
|
||||
rules::flake8_pytest_style::rules::PytestRaisesWithoutException,
|
||||
rules::flake8_pytest_style::rules::PytestRaisesTooBroad,
|
||||
rules::flake8_pytest_style::rules::PytestRaisesWithMultipleStatements,
|
||||
rules::flake8_pytest_style::rules::PytestIncorrectPytestImport,
|
||||
rules::flake8_pytest_style::rules::PytestAssertAlwaysFalse,
|
||||
rules::flake8_pytest_style::rules::PytestFailWithoutMessage,
|
||||
rules::flake8_pytest_style::rules::PytestAssertInExcept,
|
||||
rules::flake8_pytest_style::rules::PytestCompositeAssertion,
|
||||
rules::flake8_pytest_style::rules::PytestFixtureParamWithoutValue,
|
||||
rules::flake8_pytest_style::rules::PytestDeprecatedYieldFixture,
|
||||
rules::flake8_pytest_style::rules::PytestFixtureFinalizerCallback,
|
||||
rules::flake8_pytest_style::rules::PytestUselessYieldFixture,
|
||||
rules::flake8_pytest_style::rules::PytestIncorrectMarkParenthesesStyle,
|
||||
rules::flake8_pytest_style::rules::PytestUnnecessaryAsyncioMarkOnFixture,
|
||||
rules::flake8_pytest_style::rules::PytestErroneousUseFixturesOnFixture,
|
||||
rules::flake8_pytest_style::rules::PytestUseFixturesWithoutParameters,
|
||||
// flake8-pie
|
||||
rules::flake8_pie::rules::UnnecessaryPass,
|
||||
rules::flake8_pie::rules::DupeClassFieldDefinitions,
|
||||
rules::flake8_pie::rules::PreferUniqueEnums,
|
||||
rules::flake8_pie::rules::DuplicateClassFieldDefinition,
|
||||
rules::flake8_pie::rules::NonUniqueEnums,
|
||||
rules::flake8_pie::rules::UnnecessarySpread,
|
||||
rules::flake8_pie::rules::UnnecessaryDictKwargs,
|
||||
rules::flake8_pie::rules::PreferListBuiltin,
|
||||
rules::flake8_pie::rules::SingleStartsEndsWith,
|
||||
rules::flake8_pie::rules::ReimplementedListBuiltin,
|
||||
rules::flake8_pie::rules::MultipleStartsEndsWith,
|
||||
rules::flake8_pie::rules::UnnecessaryComprehensionAnyAll,
|
||||
// flake8-commas
|
||||
rules::flake8_commas::rules::TrailingCommaMissing,
|
||||
rules::flake8_commas::rules::TrailingCommaOnBareTupleProhibited,
|
||||
rules::flake8_commas::rules::TrailingCommaProhibited,
|
||||
rules::flake8_commas::rules::MissingTrailingComma,
|
||||
rules::flake8_commas::rules::TrailingCommaOnBareTuple,
|
||||
rules::flake8_commas::rules::ProhibitedTrailingComma,
|
||||
// flake8-no-pep420
|
||||
rules::flake8_no_pep420::rules::ImplicitNamespacePackage,
|
||||
// flake8-executable
|
||||
rules::flake8_executable::rules::ShebangNotExecutable,
|
||||
rules::flake8_executable::rules::ShebangMissingExecutableFile,
|
||||
rules::flake8_executable::rules::ShebangPython,
|
||||
rules::flake8_executable::rules::ShebangWhitespace,
|
||||
rules::flake8_executable::rules::ShebangNewline,
|
||||
rules::flake8_executable::rules::ShebangMissingPython,
|
||||
rules::flake8_executable::rules::ShebangLeadingWhitespace,
|
||||
rules::flake8_executable::rules::ShebangNotFirstLine,
|
||||
// flake8-type-checking
|
||||
rules::flake8_type_checking::rules::TypingOnlyFirstPartyImport,
|
||||
rules::flake8_type_checking::rules::TypingOnlyThirdPartyImport,
|
||||
@@ -552,7 +579,7 @@ ruff_macros::register_rules!(
|
||||
// tryceratops
|
||||
rules::tryceratops::rules::RaiseVanillaClass,
|
||||
rules::tryceratops::rules::RaiseVanillaArgs,
|
||||
rules::tryceratops::rules::PreferTypeError,
|
||||
rules::tryceratops::rules::TypeCheckWithoutTypeError,
|
||||
rules::tryceratops::rules::ReraiseNoCause,
|
||||
rules::tryceratops::rules::VerboseRaise,
|
||||
rules::tryceratops::rules::TryConsiderElse,
|
||||
@@ -560,31 +587,31 @@ ruff_macros::register_rules!(
|
||||
rules::tryceratops::rules::ErrorInsteadOfException,
|
||||
rules::tryceratops::rules::VerboseLogMessage,
|
||||
// flake8-use-pathlib
|
||||
rules::flake8_use_pathlib::violations::PathlibAbspath,
|
||||
rules::flake8_use_pathlib::violations::PathlibChmod,
|
||||
rules::flake8_use_pathlib::violations::PathlibMkdir,
|
||||
rules::flake8_use_pathlib::violations::PathlibMakedirs,
|
||||
rules::flake8_use_pathlib::violations::PathlibRename,
|
||||
rules::flake8_use_pathlib::violations::OsPathAbspath,
|
||||
rules::flake8_use_pathlib::violations::OsChmod,
|
||||
rules::flake8_use_pathlib::violations::OsMkdir,
|
||||
rules::flake8_use_pathlib::violations::OsMakedirs,
|
||||
rules::flake8_use_pathlib::violations::OsRename,
|
||||
rules::flake8_use_pathlib::violations::PathlibReplace,
|
||||
rules::flake8_use_pathlib::violations::PathlibRmdir,
|
||||
rules::flake8_use_pathlib::violations::PathlibRemove,
|
||||
rules::flake8_use_pathlib::violations::PathlibUnlink,
|
||||
rules::flake8_use_pathlib::violations::PathlibGetcwd,
|
||||
rules::flake8_use_pathlib::violations::PathlibExists,
|
||||
rules::flake8_use_pathlib::violations::PathlibExpanduser,
|
||||
rules::flake8_use_pathlib::violations::PathlibIsDir,
|
||||
rules::flake8_use_pathlib::violations::PathlibIsFile,
|
||||
rules::flake8_use_pathlib::violations::PathlibIsLink,
|
||||
rules::flake8_use_pathlib::violations::PathlibReadlink,
|
||||
rules::flake8_use_pathlib::violations::PathlibStat,
|
||||
rules::flake8_use_pathlib::violations::PathlibIsAbs,
|
||||
rules::flake8_use_pathlib::violations::PathlibJoin,
|
||||
rules::flake8_use_pathlib::violations::PathlibBasename,
|
||||
rules::flake8_use_pathlib::violations::PathlibDirname,
|
||||
rules::flake8_use_pathlib::violations::PathlibSamefile,
|
||||
rules::flake8_use_pathlib::violations::PathlibSplitext,
|
||||
rules::flake8_use_pathlib::violations::PathlibOpen,
|
||||
rules::flake8_use_pathlib::violations::PathlibPyPath,
|
||||
rules::flake8_use_pathlib::violations::OsRmdir,
|
||||
rules::flake8_use_pathlib::violations::OsRemove,
|
||||
rules::flake8_use_pathlib::violations::OsUnlink,
|
||||
rules::flake8_use_pathlib::violations::OsGetcwd,
|
||||
rules::flake8_use_pathlib::violations::OsPathExists,
|
||||
rules::flake8_use_pathlib::violations::OsPathExpanduser,
|
||||
rules::flake8_use_pathlib::violations::OsPathIsdir,
|
||||
rules::flake8_use_pathlib::violations::OsPathIsfile,
|
||||
rules::flake8_use_pathlib::violations::OsPathIslink,
|
||||
rules::flake8_use_pathlib::violations::OsReadlink,
|
||||
rules::flake8_use_pathlib::violations::OsStat,
|
||||
rules::flake8_use_pathlib::violations::OsPathIsabs,
|
||||
rules::flake8_use_pathlib::violations::OsPathJoin,
|
||||
rules::flake8_use_pathlib::violations::OsPathBasename,
|
||||
rules::flake8_use_pathlib::violations::OsPathDirname,
|
||||
rules::flake8_use_pathlib::violations::OsPathSamefile,
|
||||
rules::flake8_use_pathlib::violations::OsPathSplitext,
|
||||
rules::flake8_use_pathlib::violations::BuiltinOpen,
|
||||
rules::flake8_use_pathlib::violations::PyPath,
|
||||
// flake8-logging-format
|
||||
rules::flake8_logging_format::violations::LoggingStringFormat,
|
||||
rules::flake8_logging_format::violations::LoggingPercentFormat,
|
||||
@@ -605,17 +632,18 @@ ruff_macros::register_rules!(
|
||||
rules::ruff::rules::AmbiguousUnicodeCharacterString,
|
||||
rules::ruff::rules::AmbiguousUnicodeCharacterDocstring,
|
||||
rules::ruff::rules::AmbiguousUnicodeCharacterComment,
|
||||
rules::ruff::rules::UnpackInsteadOfConcatenatingToCollectionLiteral,
|
||||
rules::ruff::rules::CollectionLiteralConcatenation,
|
||||
rules::ruff::rules::AsyncioDanglingTask,
|
||||
rules::ruff::rules::UnusedNOQA,
|
||||
rules::ruff::rules::PairwiseOverZipped,
|
||||
// flake8-django
|
||||
rules::flake8_django::rules::NullableModelStringField,
|
||||
rules::flake8_django::rules::LocalsInRenderFunction,
|
||||
rules::flake8_django::rules::ExcludeWithModelForm,
|
||||
rules::flake8_django::rules::AllWithModelForm,
|
||||
rules::flake8_django::rules::ModelWithoutDunderStr,
|
||||
rules::flake8_django::rules::NonLeadingReceiverDecorator,
|
||||
rules::flake8_django::rules::DjangoNullableModelStringField,
|
||||
rules::flake8_django::rules::DjangoLocalsInRenderFunction,
|
||||
rules::flake8_django::rules::DjangoExcludeWithModelForm,
|
||||
rules::flake8_django::rules::DjangoAllWithModelForm,
|
||||
rules::flake8_django::rules::DjangoModelWithoutDunderStr,
|
||||
rules::flake8_django::rules::DjangoUnorderedBodyContentInModel,
|
||||
rules::flake8_django::rules::DjangoNonLeadingReceiverDecorator,
|
||||
);
|
||||
|
||||
pub trait AsRule {
|
||||
@@ -840,17 +868,17 @@ impl Rule {
|
||||
| Rule::DocLineTooLong
|
||||
| Rule::LineTooLong
|
||||
| Rule::MixedSpacesAndTabs
|
||||
| Rule::NoNewLineAtEndOfFile
|
||||
| Rule::MissingNewlineAtEndOfFile
|
||||
| Rule::UTF8EncodingDeclaration
|
||||
| Rule::ShebangMissingExecutableFile
|
||||
| Rule::ShebangNotExecutable
|
||||
| Rule::ShebangNewline
|
||||
| Rule::ShebangNotFirstLine
|
||||
| Rule::BidirectionalUnicode
|
||||
| Rule::ShebangPython
|
||||
| Rule::ShebangWhitespace
|
||||
| Rule::ShebangMissingPython
|
||||
| Rule::ShebangLeadingWhitespace
|
||||
| Rule::TrailingWhitespace
|
||||
| Rule::IndentationContainsTabs
|
||||
| Rule::BlankLineContainsWhitespace => LintSource::PhysicalLines,
|
||||
| Rule::TabIndentation
|
||||
| Rule::BlankLineWithWhitespace => LintSource::PhysicalLines,
|
||||
Rule::AmbiguousUnicodeCharacterComment
|
||||
| Rule::AmbiguousUnicodeCharacterDocstring
|
||||
| Rule::AmbiguousUnicodeCharacterString
|
||||
@@ -868,17 +896,17 @@ impl Rule {
|
||||
| Rule::ExtraneousParentheses
|
||||
| Rule::InvalidEscapeSequence
|
||||
| Rule::SingleLineImplicitStringConcatenation
|
||||
| Rule::TrailingCommaMissing
|
||||
| Rule::TrailingCommaOnBareTupleProhibited
|
||||
| Rule::MissingTrailingComma
|
||||
| Rule::TrailingCommaOnBareTuple
|
||||
| Rule::MultipleStatementsOnOneLineColon
|
||||
| Rule::UselessSemicolon
|
||||
| Rule::MultipleStatementsOnOneLineSemicolon
|
||||
| Rule::TrailingCommaProhibited
|
||||
| Rule::ProhibitedTrailingComma
|
||||
| Rule::TypeCommentInStub => LintSource::Tokens,
|
||||
Rule::IOError => LintSource::Io,
|
||||
Rule::UnsortedImports | Rule::MissingRequiredImport => LintSource::Imports,
|
||||
Rule::ImplicitNamespacePackage | Rule::InvalidModuleName => LintSource::Filesystem,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
Rule::IndentationWithInvalidMultiple
|
||||
| Rule::IndentationWithInvalidMultipleComment
|
||||
| Rule::MissingWhitespace
|
||||
@@ -918,7 +946,7 @@ impl Rule {
|
||||
/// Pairs of checks that shouldn't be enabled together.
|
||||
pub const INCOMPATIBLE_CODES: &[(Rule, Rule, &str); 2] = &[
|
||||
(
|
||||
Rule::NoBlankLineBeforeClass,
|
||||
Rule::BlankLineBeforeClass,
|
||||
Rule::OneBlankLineBeforeClass,
|
||||
"`one-blank-line-before-class` (D203) and `no-blank-line-before-class` (D211) are \
|
||||
incompatible. Ignoring `one-blank-line-before-class`.",
|
||||
|
||||
365
crates/ruff/src/registry/rule_set.rs
Normal file
365
crates/ruff/src/registry/rule_set.rs
Normal file
@@ -0,0 +1,365 @@
|
||||
use crate::registry::Rule;
|
||||
use ruff_macros::CacheKey;
|
||||
use std::fmt::{Debug, Formatter};
|
||||
use std::iter::FusedIterator;
|
||||
|
||||
/// A set of [`Rule`]s.
|
||||
///
|
||||
/// Uses a bitset where a bit of one signals that the Rule with that [u16] is in this set.
|
||||
#[derive(Clone, Default, CacheKey, PartialEq, Eq)]
|
||||
pub struct RuleSet([u64; 9]);
|
||||
|
||||
impl RuleSet {
|
||||
const EMPTY: [u64; 9] = [0; 9];
|
||||
|
||||
// 64 fits into a u16 without truncation
|
||||
#[allow(clippy::cast_possible_truncation)]
|
||||
const SLICE_BITS: u16 = u64::BITS as u16;
|
||||
|
||||
/// Returns an empty rule set.
|
||||
pub const fn empty() -> Self {
|
||||
Self(Self::EMPTY)
|
||||
}
|
||||
|
||||
pub fn clear(&mut self) {
|
||||
self.0 = Self::EMPTY;
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub const fn from_rule(rule: Rule) -> Self {
|
||||
let rule = rule as u16;
|
||||
|
||||
let index = (rule / Self::SLICE_BITS) as usize;
|
||||
|
||||
debug_assert!(
|
||||
index < Self::EMPTY.len(),
|
||||
"Rule index out of bounds. Increase the size of the bitset array."
|
||||
);
|
||||
|
||||
// The bit-position of this specific rule in the slice
|
||||
let shift = rule % Self::SLICE_BITS;
|
||||
// Set the index for that rule to 1
|
||||
let mask = 1 << shift;
|
||||
|
||||
let mut bits = Self::EMPTY;
|
||||
bits[index] = mask;
|
||||
|
||||
Self(bits)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub const fn from_rules(rules: &[Rule]) -> Self {
|
||||
let mut set = RuleSet::empty();
|
||||
|
||||
let mut i = 0;
|
||||
|
||||
// Uses a while because for loops are not allowed in const functions.
|
||||
while i < rules.len() {
|
||||
set = set.union(&RuleSet::from_rule(rules[i]));
|
||||
i += 1;
|
||||
}
|
||||
|
||||
set
|
||||
}
|
||||
|
||||
/// Returns the union of the two rule sets `self` and `other`
|
||||
///
|
||||
/// ## Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use ruff::registry::{Rule, RuleSet};
|
||||
/// let set_1 = RuleSet::from_rules(&[Rule::AmbiguousFunctionName, Rule::AnyType]);
|
||||
/// let set_2 = RuleSet::from_rules(&[
|
||||
/// Rule::BadQuotesInlineString,
|
||||
/// Rule::BooleanPositionalValueInFunctionCall,
|
||||
/// ]);
|
||||
///
|
||||
/// let union = set_1.union(&set_2);
|
||||
///
|
||||
/// assert!(union.contains(Rule::AmbiguousFunctionName));
|
||||
/// assert!(union.contains(Rule::AnyType));
|
||||
/// assert!(union.contains(Rule::BadQuotesInlineString));
|
||||
/// assert!(union.contains(Rule::BooleanPositionalValueInFunctionCall));
|
||||
/// ```
|
||||
#[must_use]
|
||||
pub const fn union(mut self, other: &Self) -> Self {
|
||||
let mut i = 0;
|
||||
|
||||
while i < self.0.len() {
|
||||
self.0[i] |= other.0[i];
|
||||
i += 1;
|
||||
}
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
/// Returns `self` without any of the rules contained in `other`.
|
||||
///
|
||||
/// ## Examples
|
||||
/// ```rust
|
||||
/// # use ruff::registry::{Rule, RuleSet};
|
||||
/// let set_1 = RuleSet::from_rules(&[Rule::AmbiguousFunctionName, Rule::AnyType]);
|
||||
/// let set_2 = RuleSet::from_rules(&[Rule::AmbiguousFunctionName, Rule::Debugger]);
|
||||
///
|
||||
/// let subtract = set_1.subtract(&set_2);
|
||||
///
|
||||
/// assert!(subtract.contains(Rule::AnyType));
|
||||
/// assert!(!subtract.contains(Rule::AmbiguousFunctionName));
|
||||
/// ```
|
||||
#[must_use]
|
||||
pub const fn subtract(mut self, other: &Self) -> Self {
|
||||
let mut i = 0;
|
||||
|
||||
while i < self.0.len() {
|
||||
self.0[i] ^= other.0[i];
|
||||
i += 1;
|
||||
}
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
/// Returns true if `self` and `other` contain at least one common rule.
|
||||
///
|
||||
/// ## Examples
|
||||
/// ```rust
|
||||
/// # use ruff::registry::{Rule, RuleSet};
|
||||
/// let set_1 = RuleSet::from_rules(&[Rule::AmbiguousFunctionName, Rule::AnyType]);
|
||||
///
|
||||
/// assert!(set_1.intersects(&RuleSet::from_rules(&[
|
||||
/// Rule::AnyType,
|
||||
/// Rule::BadQuotesInlineString
|
||||
/// ])));
|
||||
///
|
||||
/// assert!(!set_1.intersects(&RuleSet::from_rules(&[
|
||||
/// Rule::BooleanPositionalValueInFunctionCall,
|
||||
/// Rule::BadQuotesInlineString
|
||||
/// ])));
|
||||
/// ```
|
||||
pub const fn intersects(&self, other: &Self) -> bool {
|
||||
let mut i = 0;
|
||||
|
||||
while i < self.0.len() {
|
||||
if self.0[i] & other.0[i] != 0 {
|
||||
return true;
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
/// Returns `true` if this set contains no rules, `false` otherwise.
|
||||
///
|
||||
/// ## Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use ruff::registry::{Rule, RuleSet};
|
||||
/// assert!(RuleSet::empty().is_empty());
|
||||
/// assert!(
|
||||
/// !RuleSet::from_rules(&[Rule::AmbiguousFunctionName, Rule::BadQuotesInlineString])
|
||||
/// .is_empty()
|
||||
/// );
|
||||
/// ```
|
||||
pub const fn is_empty(&self) -> bool {
|
||||
self.len() == 0
|
||||
}
|
||||
|
||||
/// Returns the number of rules in this set.
|
||||
///
|
||||
/// ## Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use ruff::registry::{Rule, RuleSet};
|
||||
/// assert_eq!(RuleSet::empty().len(), 0);
|
||||
/// assert_eq!(
|
||||
/// RuleSet::from_rules(&[Rule::AmbiguousFunctionName, Rule::BadQuotesInlineString]).len(),
|
||||
/// 2
|
||||
/// );
|
||||
pub const fn len(&self) -> usize {
|
||||
let mut len: u32 = 0;
|
||||
|
||||
let mut i = 0;
|
||||
|
||||
while i < self.0.len() {
|
||||
len += self.0[i].count_ones();
|
||||
i += 1;
|
||||
}
|
||||
|
||||
len as usize
|
||||
}
|
||||
|
||||
/// Inserts `rule` into the set.
|
||||
///
|
||||
/// ## Examples
|
||||
/// ```rust
|
||||
/// # use ruff::registry::{Rule, RuleSet};
|
||||
/// let mut set = RuleSet::empty();
|
||||
///
|
||||
/// assert!(!set.contains(Rule::AnyType));
|
||||
///
|
||||
/// set.insert(Rule::AnyType);
|
||||
///
|
||||
/// assert!(set.contains(Rule::AnyType));
|
||||
/// ```
|
||||
pub fn insert(&mut self, rule: Rule) {
|
||||
let set = std::mem::take(self);
|
||||
*self = set.union(&RuleSet::from_rule(rule));
|
||||
}
|
||||
|
||||
/// Removes `rule` from the set.
|
||||
///
|
||||
/// ## Examples
|
||||
/// ```rust
|
||||
/// # use ruff::registry::{Rule, RuleSet};
|
||||
/// let mut set = RuleSet::from_rules(&[Rule::AmbiguousFunctionName, Rule::AnyType]);
|
||||
///
|
||||
/// set.remove(Rule::AmbiguousFunctionName);
|
||||
///
|
||||
/// assert!(set.contains(Rule::AnyType));
|
||||
/// assert!(!set.contains(Rule::AmbiguousFunctionName));
|
||||
/// ```
|
||||
pub fn remove(&mut self, rule: Rule) {
|
||||
let set = std::mem::take(self);
|
||||
*self = set.subtract(&RuleSet::from_rule(rule));
|
||||
}
|
||||
|
||||
/// Returns `true` if `rule` is in this set.
|
||||
///
|
||||
/// ## Examples
|
||||
/// ```rust
|
||||
/// # use ruff::registry::{Rule, RuleSet};
|
||||
/// let set = RuleSet::from_rules(&[Rule::AmbiguousFunctionName, Rule::AnyType]);
|
||||
///
|
||||
/// assert!(set.contains(Rule::AmbiguousFunctionName));
|
||||
/// assert!(!set.contains(Rule::BreakOutsideLoop));
|
||||
/// ```
|
||||
pub const fn contains(&self, rule: Rule) -> bool {
|
||||
let rule = rule as u16;
|
||||
let index = rule as usize / Self::SLICE_BITS as usize;
|
||||
let shift = rule % Self::SLICE_BITS;
|
||||
let mask = 1 << shift;
|
||||
|
||||
self.0[index] & mask != 0
|
||||
}
|
||||
|
||||
/// Returns an iterator over the rules in this set.
|
||||
///
|
||||
/// ## Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use ruff::registry::{Rule, RuleSet};
|
||||
/// let set = RuleSet::from_rules(&[Rule::AmbiguousFunctionName, Rule::AnyType]);
|
||||
///
|
||||
/// let iter: Vec<_> = set.iter().collect();
|
||||
///
|
||||
/// assert_eq!(iter, vec![Rule::AmbiguousFunctionName, Rule::AnyType]);
|
||||
/// ```
|
||||
pub fn iter(&self) -> RuleSetIterator {
|
||||
RuleSetIterator {
|
||||
set: self.clone(),
|
||||
index: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for RuleSet {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_set().entries(self.iter()).finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl FromIterator<Rule> for RuleSet {
|
||||
fn from_iter<T: IntoIterator<Item = Rule>>(iter: T) -> Self {
|
||||
let mut set = RuleSet::empty();
|
||||
|
||||
for rule in iter {
|
||||
set.insert(rule);
|
||||
}
|
||||
|
||||
set
|
||||
}
|
||||
}
|
||||
|
||||
impl Extend<Rule> for RuleSet {
|
||||
fn extend<T: IntoIterator<Item = Rule>>(&mut self, iter: T) {
|
||||
let set = std::mem::take(self);
|
||||
*self = set.union(&RuleSet::from_iter(iter));
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoIterator for RuleSet {
|
||||
type Item = Rule;
|
||||
type IntoIter = RuleSetIterator;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.iter()
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoIterator for &RuleSet {
|
||||
type Item = Rule;
|
||||
type IntoIter = RuleSetIterator;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.iter()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct RuleSetIterator {
|
||||
set: RuleSet,
|
||||
index: u16,
|
||||
}
|
||||
|
||||
impl Iterator for RuleSetIterator {
|
||||
type Item = Rule;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
loop {
|
||||
let slice = self.set.0.get_mut(self.index as usize)?;
|
||||
// `trailing_zeros` is guaranteed to return a value in [0;64]
|
||||
#[allow(clippy::cast_possible_truncation)]
|
||||
let bit = slice.trailing_zeros() as u16;
|
||||
|
||||
if bit < RuleSet::SLICE_BITS {
|
||||
*slice ^= 1 << bit;
|
||||
let rule_value = self.index * RuleSet::SLICE_BITS + bit;
|
||||
// SAFETY: RuleSet guarantees that only valid rules are stored in the set.
|
||||
#[allow(unsafe_code)]
|
||||
return Some(unsafe { std::mem::transmute(rule_value) });
|
||||
}
|
||||
|
||||
self.index += 1;
|
||||
}
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
let len = self.set.len();
|
||||
|
||||
(len, Some(len))
|
||||
}
|
||||
}
|
||||
|
||||
impl ExactSizeIterator for RuleSetIterator {}
|
||||
|
||||
impl FusedIterator for RuleSetIterator {}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::registry::{Rule, RuleSet};
|
||||
use strum::IntoEnumIterator;
|
||||
|
||||
/// Tests that the set can contain all rules
|
||||
#[test]
|
||||
fn test_all_rules() {
|
||||
for rule in Rule::iter() {
|
||||
let set = RuleSet::from_rule(rule);
|
||||
|
||||
assert!(set.contains(rule));
|
||||
}
|
||||
|
||||
let all_rules_set: RuleSet = Rule::iter().collect();
|
||||
let all_rules: Vec<_> = all_rules_set.iter().collect();
|
||||
let expected_rules: Vec<_> = Rule::iter().collect();
|
||||
assert_eq!(all_rules, expected_rules);
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,7 @@ use ruff_python_stdlib::path::is_python_file;
|
||||
use rustc_hash::FxHashSet;
|
||||
|
||||
use crate::fs;
|
||||
use crate::jupyter::is_jupyter_notebook;
|
||||
use crate::settings::configuration::Configuration;
|
||||
use crate::settings::pyproject::settings_toml;
|
||||
use crate::settings::{pyproject, AllSettings, Settings};
|
||||
@@ -193,15 +194,15 @@ fn match_exclusion(file_path: &str, file_basename: &str, exclusion: &globset::Gl
|
||||
exclusion.is_match(file_path) || exclusion.is_match(file_basename)
|
||||
}
|
||||
|
||||
/// Return `true` if the [`DirEntry`] appears to be that of a Python file.
|
||||
/// Return `true` if the [`DirEntry`] appears to be that of a Python file or jupyter notebook.
|
||||
pub fn is_python_entry(entry: &DirEntry) -> bool {
|
||||
is_python_file(entry.path())
|
||||
(is_python_file(entry.path()) || is_jupyter_notebook(entry.path()))
|
||||
&& !entry
|
||||
.file_type()
|
||||
.map_or(false, |file_type| file_type.is_dir())
|
||||
}
|
||||
|
||||
/// Find all Python (`.py` and `.pyi` files) in a set of paths.
|
||||
/// Find all Python (`.py`, `.pyi` and `.ipynb` files) in a set of paths.
|
||||
pub fn python_files_in_path(
|
||||
paths: &[PathBuf],
|
||||
pyproject_strategy: &PyprojectDiscovery,
|
||||
@@ -260,38 +261,6 @@ pub fn python_files_in_path(
|
||||
std::sync::Mutex::new(vec![]);
|
||||
walker.run(|| {
|
||||
Box::new(|result| {
|
||||
// Search for the `pyproject.toml` file in this directory, before we visit any
|
||||
// of its contents.
|
||||
if pyproject_strategy.is_hierarchical() {
|
||||
if let Ok(entry) = &result {
|
||||
if entry
|
||||
.file_type()
|
||||
.map_or(false, |file_type| file_type.is_dir())
|
||||
{
|
||||
match settings_toml(entry.path()) {
|
||||
Ok(Some(pyproject)) => match resolve_scoped_settings(
|
||||
&pyproject,
|
||||
&Relativity::Parent,
|
||||
processor,
|
||||
) {
|
||||
Ok((root, settings)) => {
|
||||
resolver.write().unwrap().add(root, settings);
|
||||
}
|
||||
Err(err) => {
|
||||
*error.lock().unwrap() = Err(err);
|
||||
return WalkState::Quit;
|
||||
}
|
||||
},
|
||||
Ok(None) => {}
|
||||
Err(err) => {
|
||||
*error.lock().unwrap() = Err(err);
|
||||
return WalkState::Quit;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Respect our own exclusion behavior.
|
||||
if let Ok(entry) = &result {
|
||||
if entry.depth() > 0 {
|
||||
@@ -324,6 +293,38 @@ pub fn python_files_in_path(
|
||||
}
|
||||
}
|
||||
|
||||
// Search for the `pyproject.toml` file in this directory, before we visit any
|
||||
// of its contents.
|
||||
if pyproject_strategy.is_hierarchical() {
|
||||
if let Ok(entry) = &result {
|
||||
if entry
|
||||
.file_type()
|
||||
.map_or(false, |file_type| file_type.is_dir())
|
||||
{
|
||||
match settings_toml(entry.path()) {
|
||||
Ok(Some(pyproject)) => match resolve_scoped_settings(
|
||||
&pyproject,
|
||||
&Relativity::Parent,
|
||||
processor,
|
||||
) {
|
||||
Ok((root, settings)) => {
|
||||
resolver.write().unwrap().add(root, settings);
|
||||
}
|
||||
Err(err) => {
|
||||
*error.lock().unwrap() = Err(err);
|
||||
return WalkState::Quit;
|
||||
}
|
||||
},
|
||||
Ok(None) => {}
|
||||
Err(err) => {
|
||||
*error.lock().unwrap() = Err(err);
|
||||
return WalkState::Quit;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if result.as_ref().map_or(true, |entry| {
|
||||
// Accept all files that are passed-in directly.
|
||||
(entry.depth() == 0 && entry.file_type().map_or(false, |ft| ft.is_file()))
|
||||
|
||||
@@ -13,16 +13,16 @@ mod tests {
|
||||
use crate::settings;
|
||||
use crate::test::test_path;
|
||||
|
||||
#[test_case(Rule::SysVersionSlice3Referenced, Path::new("YTT101.py"); "YTT101")]
|
||||
#[test_case(Rule::SysVersion2Referenced, Path::new("YTT102.py"); "YTT102")]
|
||||
#[test_case(Rule::SysVersionSlice3, Path::new("YTT101.py"); "YTT101")]
|
||||
#[test_case(Rule::SysVersion2, Path::new("YTT102.py"); "YTT102")]
|
||||
#[test_case(Rule::SysVersionCmpStr3, Path::new("YTT103.py"); "YTT103")]
|
||||
#[test_case(Rule::SysVersionInfo0Eq3Referenced, Path::new("YTT201.py"); "YTT201")]
|
||||
#[test_case(Rule::SixPY3Referenced, Path::new("YTT202.py"); "YTT202")]
|
||||
#[test_case(Rule::SysVersionInfo0Eq3, Path::new("YTT201.py"); "YTT201")]
|
||||
#[test_case(Rule::SixPY3, Path::new("YTT202.py"); "YTT202")]
|
||||
#[test_case(Rule::SysVersionInfo1CmpInt, Path::new("YTT203.py"); "YTT203")]
|
||||
#[test_case(Rule::SysVersionInfoMinorCmpInt, Path::new("YTT204.py"); "YTT204")]
|
||||
#[test_case(Rule::SysVersion0Referenced, Path::new("YTT301.py"); "YTT301")]
|
||||
#[test_case(Rule::SysVersion0, Path::new("YTT301.py"); "YTT301")]
|
||||
#[test_case(Rule::SysVersionCmpStr10, Path::new("YTT302.py"); "YTT302")]
|
||||
#[test_case(Rule::SysVersionSlice1Referenced, Path::new("YTT303.py"); "YTT303")]
|
||||
#[test_case(Rule::SysVersionSlice1, Path::new("YTT303.py"); "YTT303")]
|
||||
fn rules(rule_code: Rule, path: &Path) -> Result<()> {
|
||||
let snapshot = format!("{}_{}", rule_code.noqa_code(), path.to_string_lossy());
|
||||
let diagnostics = test_path(
|
||||
|
||||
@@ -9,9 +9,9 @@ use crate::checkers::ast::Checker;
|
||||
use crate::registry::Rule;
|
||||
|
||||
#[violation]
|
||||
pub struct SysVersionSlice3Referenced;
|
||||
pub struct SysVersionSlice3;
|
||||
|
||||
impl Violation for SysVersionSlice3Referenced {
|
||||
impl Violation for SysVersionSlice3 {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!("`sys.version[:3]` referenced (python3.10), use `sys.version_info`")
|
||||
@@ -19,9 +19,9 @@ impl Violation for SysVersionSlice3Referenced {
|
||||
}
|
||||
|
||||
#[violation]
|
||||
pub struct SysVersion2Referenced;
|
||||
pub struct SysVersion2;
|
||||
|
||||
impl Violation for SysVersion2Referenced {
|
||||
impl Violation for SysVersion2 {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!("`sys.version[2]` referenced (python3.10), use `sys.version_info`")
|
||||
@@ -39,9 +39,9 @@ impl Violation for SysVersionCmpStr3 {
|
||||
}
|
||||
|
||||
#[violation]
|
||||
pub struct SysVersionInfo0Eq3Referenced;
|
||||
pub struct SysVersionInfo0Eq3;
|
||||
|
||||
impl Violation for SysVersionInfo0Eq3Referenced {
|
||||
impl Violation for SysVersionInfo0Eq3 {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!("`sys.version_info[0] == 3` referenced (python4), use `>=`")
|
||||
@@ -49,9 +49,9 @@ impl Violation for SysVersionInfo0Eq3Referenced {
|
||||
}
|
||||
|
||||
#[violation]
|
||||
pub struct SixPY3Referenced;
|
||||
pub struct SixPY3;
|
||||
|
||||
impl Violation for SixPY3Referenced {
|
||||
impl Violation for SixPY3 {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!("`six.PY3` referenced (python4), use `not six.PY2`")
|
||||
@@ -85,9 +85,9 @@ impl Violation for SysVersionInfoMinorCmpInt {
|
||||
}
|
||||
|
||||
#[violation]
|
||||
pub struct SysVersion0Referenced;
|
||||
pub struct SysVersion0;
|
||||
|
||||
impl Violation for SysVersion0Referenced {
|
||||
impl Violation for SysVersion0 {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!("`sys.version[0]` referenced (python10), use `sys.version_info`")
|
||||
@@ -105,9 +105,9 @@ impl Violation for SysVersionCmpStr10 {
|
||||
}
|
||||
|
||||
#[violation]
|
||||
pub struct SysVersionSlice1Referenced;
|
||||
pub struct SysVersionSlice1;
|
||||
|
||||
impl Violation for SysVersionSlice1Referenced {
|
||||
impl Violation for SysVersionSlice1 {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!("`sys.version[:1]` referenced (python10), use `sys.version_info`")
|
||||
@@ -137,25 +137,17 @@ pub fn subscript(checker: &mut Checker, value: &Expr, slice: &Expr) {
|
||||
} = &upper.node
|
||||
{
|
||||
if *i == BigInt::from(1)
|
||||
&& checker
|
||||
.settings
|
||||
.rules
|
||||
.enabled(Rule::SysVersionSlice1Referenced)
|
||||
&& checker.settings.rules.enabled(Rule::SysVersionSlice1)
|
||||
{
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
SysVersionSlice1Referenced,
|
||||
Range::from(value),
|
||||
));
|
||||
checker
|
||||
.diagnostics
|
||||
.push(Diagnostic::new(SysVersionSlice1, Range::from(value)));
|
||||
} else if *i == BigInt::from(3)
|
||||
&& checker
|
||||
.settings
|
||||
.rules
|
||||
.enabled(Rule::SysVersionSlice3Referenced)
|
||||
&& checker.settings.rules.enabled(Rule::SysVersionSlice3)
|
||||
{
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
SysVersionSlice3Referenced,
|
||||
Range::from(value),
|
||||
));
|
||||
checker
|
||||
.diagnostics
|
||||
.push(Diagnostic::new(SysVersionSlice3, Range::from(value)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -164,18 +156,15 @@ pub fn subscript(checker: &mut Checker, value: &Expr, slice: &Expr) {
|
||||
value: Constant::Int(i),
|
||||
..
|
||||
} => {
|
||||
if *i == BigInt::from(2)
|
||||
&& checker.settings.rules.enabled(Rule::SysVersion2Referenced)
|
||||
if *i == BigInt::from(2) && checker.settings.rules.enabled(Rule::SysVersion2) {
|
||||
checker
|
||||
.diagnostics
|
||||
.push(Diagnostic::new(SysVersion2, Range::from(value)));
|
||||
} else if *i == BigInt::from(0) && checker.settings.rules.enabled(Rule::SysVersion0)
|
||||
{
|
||||
checker
|
||||
.diagnostics
|
||||
.push(Diagnostic::new(SysVersion2Referenced, Range::from(value)));
|
||||
} else if *i == BigInt::from(0)
|
||||
&& checker.settings.rules.enabled(Rule::SysVersion0Referenced)
|
||||
{
|
||||
checker
|
||||
.diagnostics
|
||||
.push(Diagnostic::new(SysVersion0Referenced, Range::from(value)));
|
||||
.push(Diagnostic::new(SysVersion0, Range::from(value)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -207,15 +196,11 @@ pub fn compare(checker: &mut Checker, left: &Expr, ops: &[Cmpop], comparators: &
|
||||
) = (ops, comparators)
|
||||
{
|
||||
if *n == BigInt::from(3)
|
||||
&& checker
|
||||
.settings
|
||||
.rules
|
||||
.enabled(Rule::SysVersionInfo0Eq3Referenced)
|
||||
&& checker.settings.rules.enabled(Rule::SysVersionInfo0Eq3)
|
||||
{
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
SysVersionInfo0Eq3Referenced,
|
||||
Range::from(left),
|
||||
));
|
||||
checker
|
||||
.diagnostics
|
||||
.push(Diagnostic::new(SysVersionInfo0Eq3, Range::from(left)));
|
||||
}
|
||||
}
|
||||
} else if *i == BigInt::from(1) {
|
||||
@@ -309,6 +294,6 @@ pub fn name_or_attribute(checker: &mut Checker, expr: &Expr) {
|
||||
{
|
||||
checker
|
||||
.diagnostics
|
||||
.push(Diagnostic::new(SixPY3Referenced, Range::from(expr)));
|
||||
.push(Diagnostic::new(SixPY3, Range::from(expr)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ source: crates/ruff/src/rules/flake8_2020/mod.rs
|
||||
expression: diagnostics
|
||||
---
|
||||
- kind:
|
||||
name: SysVersionSlice3Referenced
|
||||
name: SysVersionSlice3
|
||||
body: "`sys.version[:3]` referenced (python3.10), use `sys.version_info`"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
@@ -16,7 +16,7 @@ expression: diagnostics
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
name: SysVersionSlice3Referenced
|
||||
name: SysVersionSlice3
|
||||
body: "`sys.version[:3]` referenced (python3.10), use `sys.version_info`"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
@@ -29,7 +29,7 @@ expression: diagnostics
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
name: SysVersionSlice3Referenced
|
||||
name: SysVersionSlice3
|
||||
body: "`sys.version[:3]` referenced (python3.10), use `sys.version_info`"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
|
||||
@@ -3,7 +3,7 @@ source: crates/ruff/src/rules/flake8_2020/mod.rs
|
||||
expression: diagnostics
|
||||
---
|
||||
- kind:
|
||||
name: SysVersion2Referenced
|
||||
name: SysVersion2
|
||||
body: "`sys.version[2]` referenced (python3.10), use `sys.version_info`"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
@@ -16,7 +16,7 @@ expression: diagnostics
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
name: SysVersion2Referenced
|
||||
name: SysVersion2
|
||||
body: "`sys.version[2]` referenced (python3.10), use `sys.version_info`"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
|
||||
@@ -3,7 +3,7 @@ source: crates/ruff/src/rules/flake8_2020/mod.rs
|
||||
expression: diagnostics
|
||||
---
|
||||
- kind:
|
||||
name: SysVersionInfo0Eq3Referenced
|
||||
name: SysVersionInfo0Eq3
|
||||
body: "`sys.version_info[0] == 3` referenced (python4), use `>=`"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
@@ -16,7 +16,7 @@ expression: diagnostics
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
name: SysVersionInfo0Eq3Referenced
|
||||
name: SysVersionInfo0Eq3
|
||||
body: "`sys.version_info[0] == 3` referenced (python4), use `>=`"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
@@ -29,7 +29,7 @@ expression: diagnostics
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
name: SysVersionInfo0Eq3Referenced
|
||||
name: SysVersionInfo0Eq3
|
||||
body: "`sys.version_info[0] == 3` referenced (python4), use `>=`"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
@@ -42,7 +42,7 @@ expression: diagnostics
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
name: SysVersionInfo0Eq3Referenced
|
||||
name: SysVersionInfo0Eq3
|
||||
body: "`sys.version_info[0] == 3` referenced (python4), use `>=`"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
|
||||
@@ -3,7 +3,7 @@ source: crates/ruff/src/rules/flake8_2020/mod.rs
|
||||
expression: diagnostics
|
||||
---
|
||||
- kind:
|
||||
name: SixPY3Referenced
|
||||
name: SixPY3
|
||||
body: "`six.PY3` referenced (python4), use `not six.PY2`"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
@@ -16,7 +16,7 @@ expression: diagnostics
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
name: SixPY3Referenced
|
||||
name: SixPY3
|
||||
body: "`six.PY3` referenced (python4), use `not six.PY2`"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
|
||||
@@ -3,7 +3,7 @@ source: crates/ruff/src/rules/flake8_2020/mod.rs
|
||||
expression: diagnostics
|
||||
---
|
||||
- kind:
|
||||
name: SysVersion0Referenced
|
||||
name: SysVersion0
|
||||
body: "`sys.version[0]` referenced (python10), use `sys.version_info`"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
@@ -16,7 +16,7 @@ expression: diagnostics
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
name: SysVersion0Referenced
|
||||
name: SysVersion0
|
||||
body: "`sys.version[0]` referenced (python10), use `sys.version_info`"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
|
||||
@@ -3,7 +3,7 @@ source: crates/ruff/src/rules/flake8_2020/mod.rs
|
||||
expression: diagnostics
|
||||
---
|
||||
- kind:
|
||||
name: SysVersionSlice1Referenced
|
||||
name: SysVersionSlice1
|
||||
body: "`sys.version[:1]` referenced (python10), use `sys.version_info`"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
@@ -16,7 +16,7 @@ expression: diagnostics
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
name: SysVersionSlice1Referenced
|
||||
name: SysVersionSlice1
|
||||
body: "`sys.version[:1]` referenced (python10), use `sys.version_info`"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
|
||||
@@ -7,7 +7,7 @@ use ruff_python_ast::source_code::Locator;
|
||||
use ruff_python_ast::types::Range;
|
||||
|
||||
/// ANN204
|
||||
pub fn add_return_none_annotation(locator: &Locator, stmt: &Stmt) -> Result<Fix> {
|
||||
pub fn add_return_annotation(locator: &Locator, stmt: &Stmt, annotation: &str) -> Result<Fix> {
|
||||
let range = Range::from(stmt);
|
||||
let contents = locator.slice(range);
|
||||
|
||||
@@ -18,7 +18,7 @@ pub fn add_return_none_annotation(locator: &Locator, stmt: &Stmt) -> Result<Fix>
|
||||
for (start, tok, ..) in lexer::lex_located(contents, Mode::Module, range.location).flatten() {
|
||||
if seen_lpar && seen_rpar {
|
||||
if matches!(tok, Tok::Colon) {
|
||||
return Ok(Fix::insertion(" -> None".to_string(), start));
|
||||
return Ok(Fix::insertion(format!(" -> {annotation}"), start));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ mod tests {
|
||||
Rule::MissingTypeKwargs,
|
||||
Rule::MissingTypeSelf,
|
||||
Rule::MissingTypeCls,
|
||||
Rule::MissingReturnTypePublicFunction,
|
||||
Rule::MissingReturnTypeUndocumentedPublicFunction,
|
||||
Rule::MissingReturnTypePrivateFunction,
|
||||
Rule::MissingReturnTypeSpecialMethod,
|
||||
Rule::MissingReturnTypeStaticMethod,
|
||||
@@ -54,7 +54,7 @@ mod tests {
|
||||
Rule::MissingTypeKwargs,
|
||||
Rule::MissingTypeSelf,
|
||||
Rule::MissingTypeCls,
|
||||
Rule::MissingReturnTypePublicFunction,
|
||||
Rule::MissingReturnTypeUndocumentedPublicFunction,
|
||||
Rule::MissingReturnTypePrivateFunction,
|
||||
Rule::MissingReturnTypeSpecialMethod,
|
||||
Rule::MissingReturnTypeStaticMethod,
|
||||
@@ -99,7 +99,7 @@ mod tests {
|
||||
..Default::default()
|
||||
},
|
||||
..Settings::for_rules(vec![
|
||||
Rule::MissingReturnTypePublicFunction,
|
||||
Rule::MissingReturnTypeUndocumentedPublicFunction,
|
||||
Rule::MissingReturnTypePrivateFunction,
|
||||
Rule::MissingReturnTypeSpecialMethod,
|
||||
Rule::MissingReturnTypeStaticMethod,
|
||||
@@ -126,7 +126,7 @@ mod tests {
|
||||
Rule::MissingTypeKwargs,
|
||||
Rule::MissingTypeSelf,
|
||||
Rule::MissingTypeCls,
|
||||
Rule::MissingReturnTypePublicFunction,
|
||||
Rule::MissingReturnTypeUndocumentedPublicFunction,
|
||||
Rule::MissingReturnTypePrivateFunction,
|
||||
Rule::MissingReturnTypeSpecialMethod,
|
||||
Rule::MissingReturnTypeStaticMethod,
|
||||
@@ -161,7 +161,7 @@ mod tests {
|
||||
Path::new("flake8_annotations/allow_overload.py"),
|
||||
&Settings {
|
||||
..Settings::for_rules(vec![
|
||||
Rule::MissingReturnTypePublicFunction,
|
||||
Rule::MissingReturnTypeUndocumentedPublicFunction,
|
||||
Rule::MissingReturnTypePrivateFunction,
|
||||
Rule::MissingReturnTypeSpecialMethod,
|
||||
Rule::MissingReturnTypeStaticMethod,
|
||||
@@ -179,7 +179,7 @@ mod tests {
|
||||
Path::new("flake8_annotations/allow_nested_overload.py"),
|
||||
&Settings {
|
||||
..Settings::for_rules(vec![
|
||||
Rule::MissingReturnTypePublicFunction,
|
||||
Rule::MissingReturnTypeUndocumentedPublicFunction,
|
||||
Rule::MissingReturnTypePrivateFunction,
|
||||
Rule::MissingReturnTypeSpecialMethod,
|
||||
Rule::MissingReturnTypeStaticMethod,
|
||||
@@ -190,4 +190,14 @@ mod tests {
|
||||
assert_yaml_snapshot!(diagnostics);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn simple_magic_methods() -> Result<()> {
|
||||
let diagnostics = test_path(
|
||||
Path::new("flake8_annotations/simple_magic_methods.py"),
|
||||
&Settings::for_rule(Rule::MissingReturnTypeSpecialMethod),
|
||||
)?;
|
||||
assert_yaml_snapshot!(diagnostics);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,10 +5,11 @@ use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::helpers::ReturnStatementVisitor;
|
||||
use ruff_python_ast::types::Range;
|
||||
use ruff_python_ast::visibility;
|
||||
use ruff_python_ast::visibility::Visibility;
|
||||
use ruff_python_ast::visibility::{self};
|
||||
use ruff_python_ast::visitor::Visitor;
|
||||
use ruff_python_ast::{cast, helpers};
|
||||
use ruff_python_stdlib::typing::SIMPLE_MAGIC_RETURN_TYPES;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::docstrings::definition::{Definition, DefinitionKind};
|
||||
@@ -209,14 +210,14 @@ impl Violation for MissingTypeCls {
|
||||
/// return a + b
|
||||
/// ```
|
||||
#[violation]
|
||||
pub struct MissingReturnTypePublicFunction {
|
||||
pub struct MissingReturnTypeUndocumentedPublicFunction {
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
impl Violation for MissingReturnTypePublicFunction {
|
||||
impl Violation for MissingReturnTypeUndocumentedPublicFunction {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
let MissingReturnTypePublicFunction { name } = self;
|
||||
let MissingReturnTypeUndocumentedPublicFunction { name } = self;
|
||||
format!("Missing return type annotation for public function `{name}`")
|
||||
}
|
||||
}
|
||||
@@ -650,7 +651,7 @@ pub fn definition(
|
||||
helpers::identifier_range(stmt, checker.locator),
|
||||
));
|
||||
}
|
||||
} else if is_method && visibility::is_init(cast::name(stmt)) {
|
||||
} else if is_method && visibility::is_init(name) {
|
||||
// Allow omission of return annotation in `__init__` functions, as long as at
|
||||
// least one argument is typed.
|
||||
if checker
|
||||
@@ -667,7 +668,7 @@ pub fn definition(
|
||||
helpers::identifier_range(stmt, checker.locator),
|
||||
);
|
||||
if checker.patch(diagnostic.kind.rule()) {
|
||||
match fixes::add_return_none_annotation(checker.locator, stmt) {
|
||||
match fixes::add_return_annotation(checker.locator, stmt, "None") {
|
||||
Ok(fix) => {
|
||||
diagnostic.amend(fix);
|
||||
}
|
||||
@@ -677,18 +678,30 @@ pub fn definition(
|
||||
diagnostics.push(diagnostic);
|
||||
}
|
||||
}
|
||||
} else if is_method && visibility::is_magic(cast::name(stmt)) {
|
||||
} else if is_method && visibility::is_magic(name) {
|
||||
if checker
|
||||
.settings
|
||||
.rules
|
||||
.enabled(Rule::MissingReturnTypeSpecialMethod)
|
||||
{
|
||||
diagnostics.push(Diagnostic::new(
|
||||
let mut diagnostic = Diagnostic::new(
|
||||
MissingReturnTypeSpecialMethod {
|
||||
name: name.to_string(),
|
||||
},
|
||||
helpers::identifier_range(stmt, checker.locator),
|
||||
));
|
||||
);
|
||||
let return_type = SIMPLE_MAGIC_RETURN_TYPES.get(name);
|
||||
if let Some(return_type) = return_type {
|
||||
if checker.patch(diagnostic.kind.rule()) {
|
||||
match fixes::add_return_annotation(checker.locator, stmt, return_type) {
|
||||
Ok(fix) => {
|
||||
diagnostic.amend(fix);
|
||||
}
|
||||
Err(e) => error!("Failed to generate fix: {e}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
diagnostics.push(diagnostic);
|
||||
}
|
||||
} else {
|
||||
match visibility {
|
||||
@@ -696,10 +709,10 @@ pub fn definition(
|
||||
if checker
|
||||
.settings
|
||||
.rules
|
||||
.enabled(Rule::MissingReturnTypePublicFunction)
|
||||
.enabled(Rule::MissingReturnTypeUndocumentedPublicFunction)
|
||||
{
|
||||
diagnostics.push(Diagnostic::new(
|
||||
MissingReturnTypePublicFunction {
|
||||
MissingReturnTypeUndocumentedPublicFunction {
|
||||
name: name.to_string(),
|
||||
},
|
||||
helpers::identifier_range(stmt, checker.locator),
|
||||
|
||||
@@ -3,7 +3,7 @@ source: crates/ruff/src/rules/flake8_annotations/mod.rs
|
||||
expression: diagnostics
|
||||
---
|
||||
- kind:
|
||||
name: MissingReturnTypePublicFunction
|
||||
name: MissingReturnTypeUndocumentedPublicFunction
|
||||
body: "Missing return type annotation for public function `bar`"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
|
||||
@@ -3,7 +3,7 @@ source: crates/ruff/src/rules/flake8_annotations/mod.rs
|
||||
expression: diagnostics
|
||||
---
|
||||
- kind:
|
||||
name: MissingReturnTypePublicFunction
|
||||
name: MissingReturnTypeUndocumentedPublicFunction
|
||||
body: "Missing return type annotation for public function `foo`"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
@@ -42,7 +42,7 @@ expression: diagnostics
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
name: MissingReturnTypePublicFunction
|
||||
name: MissingReturnTypeUndocumentedPublicFunction
|
||||
body: "Missing return type annotation for public function `foo`"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
@@ -81,7 +81,7 @@ expression: diagnostics
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
name: MissingReturnTypePublicFunction
|
||||
name: MissingReturnTypeUndocumentedPublicFunction
|
||||
body: "Missing return type annotation for public function `foo`"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
@@ -94,7 +94,7 @@ expression: diagnostics
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
name: MissingReturnTypePublicFunction
|
||||
name: MissingReturnTypeUndocumentedPublicFunction
|
||||
body: "Missing return type annotation for public function `foo`"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
|
||||
@@ -3,7 +3,7 @@ source: crates/ruff/src/rules/flake8_annotations/mod.rs
|
||||
expression: diagnostics
|
||||
---
|
||||
- kind:
|
||||
name: MissingReturnTypePublicFunction
|
||||
name: MissingReturnTypeUndocumentedPublicFunction
|
||||
body: "Missing return type annotation for public function `error_partially_typed_1`"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
@@ -42,7 +42,7 @@ expression: diagnostics
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
name: MissingReturnTypePublicFunction
|
||||
name: MissingReturnTypeUndocumentedPublicFunction
|
||||
body: "Missing return type annotation for public function `error_partially_typed_3`"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
@@ -55,7 +55,7 @@ expression: diagnostics
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
name: MissingReturnTypePublicFunction
|
||||
name: MissingReturnTypeUndocumentedPublicFunction
|
||||
body: "Missing return type annotation for public function `error_typed_self`"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
|
||||
@@ -0,0 +1,285 @@
|
||||
---
|
||||
source: crates/ruff/src/rules/flake8_annotations/mod.rs
|
||||
expression: diagnostics
|
||||
---
|
||||
- kind:
|
||||
name: MissingReturnTypeSpecialMethod
|
||||
body: "Missing return type annotation for special method `__str__`"
|
||||
suggestion: "Add `None` return type"
|
||||
fixable: true
|
||||
location:
|
||||
row: 2
|
||||
column: 8
|
||||
end_location:
|
||||
row: 2
|
||||
column: 15
|
||||
fix:
|
||||
content: " -> str"
|
||||
location:
|
||||
row: 2
|
||||
column: 21
|
||||
end_location:
|
||||
row: 2
|
||||
column: 21
|
||||
parent: ~
|
||||
- kind:
|
||||
name: MissingReturnTypeSpecialMethod
|
||||
body: "Missing return type annotation for special method `__repr__`"
|
||||
suggestion: "Add `None` return type"
|
||||
fixable: true
|
||||
location:
|
||||
row: 5
|
||||
column: 8
|
||||
end_location:
|
||||
row: 5
|
||||
column: 16
|
||||
fix:
|
||||
content: " -> str"
|
||||
location:
|
||||
row: 5
|
||||
column: 22
|
||||
end_location:
|
||||
row: 5
|
||||
column: 22
|
||||
parent: ~
|
||||
- kind:
|
||||
name: MissingReturnTypeSpecialMethod
|
||||
body: "Missing return type annotation for special method `__len__`"
|
||||
suggestion: "Add `None` return type"
|
||||
fixable: true
|
||||
location:
|
||||
row: 8
|
||||
column: 8
|
||||
end_location:
|
||||
row: 8
|
||||
column: 15
|
||||
fix:
|
||||
content: " -> int"
|
||||
location:
|
||||
row: 8
|
||||
column: 21
|
||||
end_location:
|
||||
row: 8
|
||||
column: 21
|
||||
parent: ~
|
||||
- kind:
|
||||
name: MissingReturnTypeSpecialMethod
|
||||
body: "Missing return type annotation for special method `__length_hint__`"
|
||||
suggestion: "Add `None` return type"
|
||||
fixable: true
|
||||
location:
|
||||
row: 11
|
||||
column: 8
|
||||
end_location:
|
||||
row: 11
|
||||
column: 23
|
||||
fix:
|
||||
content: " -> int"
|
||||
location:
|
||||
row: 11
|
||||
column: 29
|
||||
end_location:
|
||||
row: 11
|
||||
column: 29
|
||||
parent: ~
|
||||
- kind:
|
||||
name: MissingReturnTypeSpecialMethod
|
||||
body: "Missing return type annotation for special method `__init__`"
|
||||
suggestion: "Add `None` return type"
|
||||
fixable: true
|
||||
location:
|
||||
row: 14
|
||||
column: 8
|
||||
end_location:
|
||||
row: 14
|
||||
column: 16
|
||||
fix:
|
||||
content: " -> None"
|
||||
location:
|
||||
row: 14
|
||||
column: 22
|
||||
end_location:
|
||||
row: 14
|
||||
column: 22
|
||||
parent: ~
|
||||
- kind:
|
||||
name: MissingReturnTypeSpecialMethod
|
||||
body: "Missing return type annotation for special method `__del__`"
|
||||
suggestion: "Add `None` return type"
|
||||
fixable: true
|
||||
location:
|
||||
row: 17
|
||||
column: 8
|
||||
end_location:
|
||||
row: 17
|
||||
column: 15
|
||||
fix:
|
||||
content: " -> None"
|
||||
location:
|
||||
row: 17
|
||||
column: 21
|
||||
end_location:
|
||||
row: 17
|
||||
column: 21
|
||||
parent: ~
|
||||
- kind:
|
||||
name: MissingReturnTypeSpecialMethod
|
||||
body: "Missing return type annotation for special method `__bool__`"
|
||||
suggestion: "Add `None` return type"
|
||||
fixable: true
|
||||
location:
|
||||
row: 20
|
||||
column: 8
|
||||
end_location:
|
||||
row: 20
|
||||
column: 16
|
||||
fix:
|
||||
content: " -> bool"
|
||||
location:
|
||||
row: 20
|
||||
column: 22
|
||||
end_location:
|
||||
row: 20
|
||||
column: 22
|
||||
parent: ~
|
||||
- kind:
|
||||
name: MissingReturnTypeSpecialMethod
|
||||
body: "Missing return type annotation for special method `__bytes__`"
|
||||
suggestion: "Add `None` return type"
|
||||
fixable: true
|
||||
location:
|
||||
row: 23
|
||||
column: 8
|
||||
end_location:
|
||||
row: 23
|
||||
column: 17
|
||||
fix:
|
||||
content: " -> bytes"
|
||||
location:
|
||||
row: 23
|
||||
column: 23
|
||||
end_location:
|
||||
row: 23
|
||||
column: 23
|
||||
parent: ~
|
||||
- kind:
|
||||
name: MissingReturnTypeSpecialMethod
|
||||
body: "Missing return type annotation for special method `__format__`"
|
||||
suggestion: "Add `None` return type"
|
||||
fixable: true
|
||||
location:
|
||||
row: 26
|
||||
column: 8
|
||||
end_location:
|
||||
row: 26
|
||||
column: 18
|
||||
fix:
|
||||
content: " -> str"
|
||||
location:
|
||||
row: 26
|
||||
column: 37
|
||||
end_location:
|
||||
row: 26
|
||||
column: 37
|
||||
parent: ~
|
||||
- kind:
|
||||
name: MissingReturnTypeSpecialMethod
|
||||
body: "Missing return type annotation for special method `__contains__`"
|
||||
suggestion: "Add `None` return type"
|
||||
fixable: true
|
||||
location:
|
||||
row: 29
|
||||
column: 8
|
||||
end_location:
|
||||
row: 29
|
||||
column: 20
|
||||
fix:
|
||||
content: " -> bool"
|
||||
location:
|
||||
row: 29
|
||||
column: 32
|
||||
end_location:
|
||||
row: 29
|
||||
column: 32
|
||||
parent: ~
|
||||
- kind:
|
||||
name: MissingReturnTypeSpecialMethod
|
||||
body: "Missing return type annotation for special method `__complex__`"
|
||||
suggestion: "Add `None` return type"
|
||||
fixable: true
|
||||
location:
|
||||
row: 32
|
||||
column: 8
|
||||
end_location:
|
||||
row: 32
|
||||
column: 19
|
||||
fix:
|
||||
content: " -> complex"
|
||||
location:
|
||||
row: 32
|
||||
column: 25
|
||||
end_location:
|
||||
row: 32
|
||||
column: 25
|
||||
parent: ~
|
||||
- kind:
|
||||
name: MissingReturnTypeSpecialMethod
|
||||
body: "Missing return type annotation for special method `__int__`"
|
||||
suggestion: "Add `None` return type"
|
||||
fixable: true
|
||||
location:
|
||||
row: 35
|
||||
column: 8
|
||||
end_location:
|
||||
row: 35
|
||||
column: 15
|
||||
fix:
|
||||
content: " -> int"
|
||||
location:
|
||||
row: 35
|
||||
column: 21
|
||||
end_location:
|
||||
row: 35
|
||||
column: 21
|
||||
parent: ~
|
||||
- kind:
|
||||
name: MissingReturnTypeSpecialMethod
|
||||
body: "Missing return type annotation for special method `__float__`"
|
||||
suggestion: "Add `None` return type"
|
||||
fixable: true
|
||||
location:
|
||||
row: 38
|
||||
column: 8
|
||||
end_location:
|
||||
row: 38
|
||||
column: 17
|
||||
fix:
|
||||
content: " -> float"
|
||||
location:
|
||||
row: 38
|
||||
column: 23
|
||||
end_location:
|
||||
row: 38
|
||||
column: 23
|
||||
parent: ~
|
||||
- kind:
|
||||
name: MissingReturnTypeSpecialMethod
|
||||
body: "Missing return type annotation for special method `__index__`"
|
||||
suggestion: "Add `None` return type"
|
||||
fixable: true
|
||||
location:
|
||||
row: 41
|
||||
column: 8
|
||||
end_location:
|
||||
row: 41
|
||||
column: 17
|
||||
fix:
|
||||
content: " -> int"
|
||||
location:
|
||||
row: 41
|
||||
column: 23
|
||||
end_location:
|
||||
row: 41
|
||||
column: 23
|
||||
parent: ~
|
||||
|
||||
@@ -3,7 +3,7 @@ source: crates/ruff/src/rules/flake8_annotations/mod.rs
|
||||
expression: diagnostics
|
||||
---
|
||||
- kind:
|
||||
name: MissingReturnTypePublicFunction
|
||||
name: MissingReturnTypeUndocumentedPublicFunction
|
||||
body: "Missing return type annotation for public function `foo`"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
@@ -16,7 +16,7 @@ expression: diagnostics
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
name: MissingReturnTypePublicFunction
|
||||
name: MissingReturnTypeUndocumentedPublicFunction
|
||||
body: "Missing return type annotation for public function `foo`"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
|
||||
@@ -16,24 +16,26 @@ mod tests {
|
||||
use crate::test::test_path;
|
||||
|
||||
#[test_case(Rule::Assert, Path::new("S101.py"); "S101")]
|
||||
#[test_case(Rule::ExecBuiltin, Path::new("S102.py"); "S102")]
|
||||
#[test_case(Rule::BadFilePermissions, Path::new("S103.py"); "S103")]
|
||||
#[test_case(Rule::ExecBuiltin, Path::new("S102.py"); "S102")]
|
||||
#[test_case(Rule::HardcodedBindAllInterfaces, Path::new("S104.py"); "S104")]
|
||||
#[test_case(Rule::HardcodedPasswordString, Path::new("S105.py"); "S105")]
|
||||
#[test_case(Rule::HardcodedPasswordFuncArg, Path::new("S106.py"); "S106")]
|
||||
#[test_case(Rule::HardcodedPasswordDefault, Path::new("S107.py"); "S107")]
|
||||
#[test_case(Rule::HardcodedPasswordFuncArg, Path::new("S106.py"); "S106")]
|
||||
#[test_case(Rule::HardcodedPasswordString, Path::new("S105.py"); "S105")]
|
||||
#[test_case(Rule::HardcodedSQLExpression, Path::new("S608.py"); "S608")]
|
||||
#[test_case(Rule::HardcodedTempFile, Path::new("S108.py"); "S108")]
|
||||
#[test_case(Rule::RequestWithoutTimeout, Path::new("S113.py"); "S113")]
|
||||
#[test_case(Rule::HashlibInsecureHashFunction, Path::new("S324.py"); "S324")]
|
||||
#[test_case(Rule::Jinja2AutoescapeFalse, Path::new("S701.py"); "S701")]
|
||||
#[test_case(Rule::LoggingConfigInsecureListen, Path::new("S612.py"); "S612")]
|
||||
#[test_case(Rule::RequestWithNoCertValidation, Path::new("S501.py"); "S501")]
|
||||
#[test_case(Rule::UnsafeYAMLLoad, Path::new("S506.py"); "S506")]
|
||||
#[test_case(Rule::RequestWithoutTimeout, Path::new("S113.py"); "S113")]
|
||||
#[test_case(Rule::SnmpInsecureVersion, Path::new("S508.py"); "S508")]
|
||||
#[test_case(Rule::SnmpWeakCryptography, Path::new("S509.py"); "S509")]
|
||||
#[test_case(Rule::LoggingConfigInsecureListen, Path::new("S612.py"); "S612")]
|
||||
#[test_case(Rule::Jinja2AutoescapeFalse, Path::new("S701.py"); "S701")]
|
||||
#[test_case(Rule::TryExceptPass, Path::new("S110.py"); "S110")]
|
||||
#[test_case(Rule::SuspiciousPickleUsage, Path::new("S301.py"); "S301")]
|
||||
#[test_case(Rule::SuspiciousTelnetUsage, Path::new("S312.py"); "S312")]
|
||||
#[test_case(Rule::TryExceptContinue, Path::new("S112.py"); "S112")]
|
||||
#[test_case(Rule::TryExceptPass, Path::new("S110.py"); "S110")]
|
||||
#[test_case(Rule::UnsafeYAMLLoad, Path::new("S506.py"); "S506")]
|
||||
fn rules(rule_code: Rule, path: &Path) -> Result<()> {
|
||||
let snapshot = format!("{}_{}", rule_code.noqa_code(), path.to_string_lossy());
|
||||
let diagnostics = test_path(
|
||||
|
||||
@@ -24,6 +24,16 @@ pub use request_with_no_cert_validation::{
|
||||
pub use request_without_timeout::{request_without_timeout, RequestWithoutTimeout};
|
||||
pub use snmp_insecure_version::{snmp_insecure_version, SnmpInsecureVersion};
|
||||
pub use snmp_weak_cryptography::{snmp_weak_cryptography, SnmpWeakCryptography};
|
||||
pub use suspicious_function_call::{
|
||||
suspicious_function_call, SuspiciousEvalUsage, SuspiciousFTPLibUsage,
|
||||
SuspiciousInsecureCipherModeUsage, SuspiciousInsecureCipherUsage, SuspiciousInsecureHashUsage,
|
||||
SuspiciousMarkSafeUsage, SuspiciousMarshalUsage, SuspiciousMktempUsage,
|
||||
SuspiciousNonCryptographicRandomUsage, SuspiciousPickleUsage, SuspiciousTelnetUsage,
|
||||
SuspiciousURLOpenUsage, SuspiciousUnverifiedContextUsage, SuspiciousXMLCElementTreeUsage,
|
||||
SuspiciousXMLETreeUsage, SuspiciousXMLElementTreeUsage, SuspiciousXMLExpatBuilderUsage,
|
||||
SuspiciousXMLExpatReaderUsage, SuspiciousXMLMiniDOMUsage, SuspiciousXMLPullDOMUsage,
|
||||
SuspiciousXMLSaxUsage,
|
||||
};
|
||||
pub use try_except_continue::{try_except_continue, TryExceptContinue};
|
||||
pub use try_except_pass::{try_except_pass, TryExceptPass};
|
||||
pub use unsafe_yaml_load::{unsafe_yaml_load, UnsafeYAMLLoad};
|
||||
@@ -44,6 +54,7 @@ mod request_with_no_cert_validation;
|
||||
mod request_without_timeout;
|
||||
mod snmp_insecure_version;
|
||||
mod snmp_weak_cryptography;
|
||||
mod suspicious_function_call;
|
||||
mod try_except_continue;
|
||||
mod try_except_pass;
|
||||
mod unsafe_yaml_load;
|
||||
|
||||
@@ -0,0 +1,519 @@
|
||||
//! Check for calls to suspicious functions, or calls into suspicious modules.
|
||||
//!
|
||||
//! See: <https://bandit.readthedocs.io/en/latest/blacklists/blacklist_calls.html>
|
||||
use rustpython_parser::ast::{Expr, ExprKind};
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, DiagnosticKind, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::types::Range;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::registry::AsRule;
|
||||
|
||||
#[violation]
|
||||
pub struct SuspiciousPickleUsage;
|
||||
|
||||
impl Violation for SuspiciousPickleUsage {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!("`pickle` and modules that wrap it can be unsafe when used to deserialize untrusted data, possible security issue")
|
||||
}
|
||||
}
|
||||
|
||||
#[violation]
|
||||
pub struct SuspiciousMarshalUsage;
|
||||
|
||||
impl Violation for SuspiciousMarshalUsage {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!("Deserialization with the `marshal` module is possibly dangerous")
|
||||
}
|
||||
}
|
||||
|
||||
#[violation]
|
||||
pub struct SuspiciousInsecureHashUsage;
|
||||
|
||||
impl Violation for SuspiciousInsecureHashUsage {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!("Use of insecure MD2, MD4, MD5, or SHA1 hash function")
|
||||
}
|
||||
}
|
||||
|
||||
#[violation]
|
||||
pub struct SuspiciousInsecureCipherUsage;
|
||||
|
||||
impl Violation for SuspiciousInsecureCipherUsage {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!("Use of insecure cipher, replace with a known secure cipher such as AES")
|
||||
}
|
||||
}
|
||||
|
||||
#[violation]
|
||||
pub struct SuspiciousInsecureCipherModeUsage;
|
||||
|
||||
impl Violation for SuspiciousInsecureCipherModeUsage {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!("Use of insecure cipher mode, replace with a known secure cipher such as AES")
|
||||
}
|
||||
}
|
||||
|
||||
#[violation]
|
||||
pub struct SuspiciousMktempUsage;
|
||||
|
||||
impl Violation for SuspiciousMktempUsage {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!("Use of insecure and deprecated function (`mktemp`)")
|
||||
}
|
||||
}
|
||||
|
||||
#[violation]
|
||||
pub struct SuspiciousEvalUsage;
|
||||
|
||||
impl Violation for SuspiciousEvalUsage {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!("Use of possibly insecure function; consider using `ast.literal_eval`")
|
||||
}
|
||||
}
|
||||
|
||||
#[violation]
|
||||
pub struct SuspiciousMarkSafeUsage;
|
||||
|
||||
impl Violation for SuspiciousMarkSafeUsage {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!("Use of `mark_safe` may expose cross-site scripting vulnerabilities")
|
||||
}
|
||||
}
|
||||
|
||||
#[violation]
|
||||
pub struct SuspiciousURLOpenUsage;
|
||||
|
||||
impl Violation for SuspiciousURLOpenUsage {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!("Audit URL open for permitted schemes. Allowing use of `file:` or custom schemes is often unexpected.")
|
||||
}
|
||||
}
|
||||
|
||||
#[violation]
|
||||
pub struct SuspiciousNonCryptographicRandomUsage;
|
||||
|
||||
impl Violation for SuspiciousNonCryptographicRandomUsage {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!("Standard pseudo-random generators are not suitable for cryptographic purposes")
|
||||
}
|
||||
}
|
||||
|
||||
#[violation]
|
||||
pub struct SuspiciousXMLCElementTreeUsage;
|
||||
|
||||
impl Violation for SuspiciousXMLCElementTreeUsage {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!("Using `xml` to parse untrusted data is known to be vulnerable to XML attacks; use `defusedxml` equivalents")
|
||||
}
|
||||
}
|
||||
|
||||
#[violation]
|
||||
pub struct SuspiciousXMLElementTreeUsage;
|
||||
|
||||
impl Violation for SuspiciousXMLElementTreeUsage {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!("Using `xml` to parse untrusted data is known to be vulnerable to XML attacks; use `defusedxml` equivalents")
|
||||
}
|
||||
}
|
||||
|
||||
#[violation]
|
||||
pub struct SuspiciousXMLExpatReaderUsage;
|
||||
|
||||
impl Violation for SuspiciousXMLExpatReaderUsage {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!("Using `xml` to parse untrusted data is known to be vulnerable to XML attacks; use `defusedxml` equivalents")
|
||||
}
|
||||
}
|
||||
|
||||
#[violation]
|
||||
pub struct SuspiciousXMLExpatBuilderUsage;
|
||||
|
||||
impl Violation for SuspiciousXMLExpatBuilderUsage {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!("Using `xml` to parse untrusted data is known to be vulnerable to XML attacks; use `defusedxml` equivalents")
|
||||
}
|
||||
}
|
||||
|
||||
#[violation]
|
||||
pub struct SuspiciousXMLSaxUsage;
|
||||
|
||||
impl Violation for SuspiciousXMLSaxUsage {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!("Using `xml` to parse untrusted data is known to be vulnerable to XML attacks; use `defusedxml` equivalents")
|
||||
}
|
||||
}
|
||||
|
||||
#[violation]
|
||||
pub struct SuspiciousXMLMiniDOMUsage;
|
||||
|
||||
impl Violation for SuspiciousXMLMiniDOMUsage {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!("Using `xml` to parse untrusted data is known to be vulnerable to XML attacks; use `defusedxml` equivalents")
|
||||
}
|
||||
}
|
||||
|
||||
#[violation]
|
||||
pub struct SuspiciousXMLPullDOMUsage;
|
||||
|
||||
impl Violation for SuspiciousXMLPullDOMUsage {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!("Using `xml` to parse untrusted data is known to be vulnerable to XML attacks; use `defusedxml` equivalents")
|
||||
}
|
||||
}
|
||||
|
||||
#[violation]
|
||||
pub struct SuspiciousXMLETreeUsage;
|
||||
|
||||
impl Violation for SuspiciousXMLETreeUsage {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!("Using `xml` to parse untrusted data is known to be vulnerable to XML attacks; use `defusedxml` equivalents")
|
||||
}
|
||||
}
|
||||
|
||||
#[violation]
|
||||
pub struct SuspiciousUnverifiedContextUsage;
|
||||
|
||||
impl Violation for SuspiciousUnverifiedContextUsage {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!("Python allows using an insecure context via the `_create_unverified_context` that reverts to the previous behavior that does not validate certificates or perform hostname checks.")
|
||||
}
|
||||
}
|
||||
|
||||
#[violation]
|
||||
pub struct SuspiciousTelnetUsage;
|
||||
|
||||
impl Violation for SuspiciousTelnetUsage {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!("Telnet-related functions are being called. Telnet is considered insecure. Use SSH or some other encrypted protocol.")
|
||||
}
|
||||
}
|
||||
|
||||
#[violation]
|
||||
pub struct SuspiciousFTPLibUsage;
|
||||
|
||||
impl Violation for SuspiciousFTPLibUsage {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!("FTP-related functions are being called. FTP is considered insecure. Use SSH/SFTP/SCP or some other encrypted protocol.")
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||
pub enum Reason {
|
||||
Pickle,
|
||||
Marshal,
|
||||
InsecureHash,
|
||||
InsecureCipher,
|
||||
InsecureCipherMode,
|
||||
Mktemp,
|
||||
Eval,
|
||||
MarkSafe,
|
||||
URLOpen,
|
||||
NonCryptographicRandom,
|
||||
XMLCElementTree,
|
||||
XMLElementTree,
|
||||
XMLExpatReader,
|
||||
XMLExpatBuilder,
|
||||
XMLSax,
|
||||
XMLMiniDOM,
|
||||
XMLPullDOM,
|
||||
XMLETree,
|
||||
UnverifiedContext,
|
||||
Telnet,
|
||||
FTPLib,
|
||||
}
|
||||
|
||||
struct SuspiciousMembers<'a> {
|
||||
members: &'a [&'a [&'a str]],
|
||||
reason: Reason,
|
||||
}
|
||||
|
||||
impl<'a> SuspiciousMembers<'a> {
|
||||
pub const fn new(members: &'a [&'a [&'a str]], reason: Reason) -> Self {
|
||||
Self { members, reason }
|
||||
}
|
||||
}
|
||||
|
||||
struct SuspiciousModule<'a> {
|
||||
name: &'a str,
|
||||
reason: Reason,
|
||||
}
|
||||
|
||||
impl<'a> SuspiciousModule<'a> {
|
||||
pub const fn new(name: &'a str, reason: Reason) -> Self {
|
||||
Self { name, reason }
|
||||
}
|
||||
}
|
||||
|
||||
const SUSPICIOUS_MEMBERS: &[SuspiciousMembers] = &[
|
||||
SuspiciousMembers::new(
|
||||
&[
|
||||
&["pickle", "loads"],
|
||||
&["pickle", "load"],
|
||||
&["pickle", "Unpickler"],
|
||||
&["dill", "loads"],
|
||||
&["dill", "load"],
|
||||
&["dill", "Unpickler"],
|
||||
&["shelve", "open"],
|
||||
&["shelve", "DbfilenameShelf"],
|
||||
&["jsonpickle", "decode"],
|
||||
&["jsonpickle", "unpickler", "decode"],
|
||||
&["pandas", "read_pickle"],
|
||||
],
|
||||
Reason::Pickle,
|
||||
),
|
||||
SuspiciousMembers::new(
|
||||
&[&["marshal", "loads"], &["marshal", "load"]],
|
||||
Reason::Marshal,
|
||||
),
|
||||
SuspiciousMembers::new(
|
||||
&[
|
||||
&["Crypto", "Hash", "MD5", "new"],
|
||||
&["Crypto", "Hash", "MD4", "new"],
|
||||
&["Crypto", "Hash", "MD3", "new"],
|
||||
&["Crypto", "Hash", "MD2", "new"],
|
||||
&["Crypto", "Hash", "SHA", "new"],
|
||||
&["Cryptodome", "Hash", "MD5", "new"],
|
||||
&["Cryptodome", "Hash", "MD4", "new"],
|
||||
&["Cryptodome", "Hash", "MD3", "new"],
|
||||
&["Cryptodome", "Hash", "MD2", "new"],
|
||||
&["Cryptodome", "Hash", "SHA", "new"],
|
||||
&["cryptography", "hazmat", "primitives", "hashes", "MD5"],
|
||||
&["cryptography", "hazmat", "primitives", "hashes", "SHA1"],
|
||||
],
|
||||
Reason::InsecureHash,
|
||||
),
|
||||
SuspiciousMembers::new(
|
||||
&[
|
||||
&["Crypto", "Cipher", "ARC2", "new"],
|
||||
&["Crypto", "Cipher", "ARC2", "new"],
|
||||
&["Crypto", "Cipher", "Blowfish", "new"],
|
||||
&["Crypto", "Cipher", "DES", "new"],
|
||||
&["Crypto", "Cipher", "XOR", "new"],
|
||||
&["Cryptodome", "Cipher", "ARC2", "new"],
|
||||
&["Cryptodome", "Cipher", "ARC2", "new"],
|
||||
&["Cryptodome", "Cipher", "Blowfish", "new"],
|
||||
&["Cryptodome", "Cipher", "DES", "new"],
|
||||
&["Cryptodome", "Cipher", "XOR", "new"],
|
||||
&[
|
||||
"cryptography",
|
||||
"hazmat",
|
||||
"primitives",
|
||||
"ciphers",
|
||||
"algorithms",
|
||||
"ARC4",
|
||||
],
|
||||
&[
|
||||
"cryptography",
|
||||
"hazmat",
|
||||
"primitives",
|
||||
"ciphers",
|
||||
"algorithms",
|
||||
"Blowfish",
|
||||
],
|
||||
&[
|
||||
"cryptography",
|
||||
"hazmat",
|
||||
"primitives",
|
||||
"ciphers",
|
||||
"algorithms",
|
||||
"IDEA",
|
||||
],
|
||||
],
|
||||
Reason::InsecureCipher,
|
||||
),
|
||||
SuspiciousMembers::new(
|
||||
&[&[
|
||||
"cryptography",
|
||||
"hazmat",
|
||||
"primitives",
|
||||
"ciphers",
|
||||
"modes",
|
||||
"ECB",
|
||||
]],
|
||||
Reason::InsecureCipherMode,
|
||||
),
|
||||
SuspiciousMembers::new(&[&["tempfile", "mktemp"]], Reason::Mktemp),
|
||||
SuspiciousMembers::new(&[&["eval"]], Reason::Eval),
|
||||
SuspiciousMembers::new(
|
||||
&[&["django", "utils", "safestring", "mark_safe"]],
|
||||
Reason::MarkSafe,
|
||||
),
|
||||
SuspiciousMembers::new(
|
||||
&[
|
||||
&["urllib", "urlopen"],
|
||||
&["urllib", "request", "urlopen"],
|
||||
&["urllib", "urlretrieve"],
|
||||
&["urllib", "request", "urlretrieve"],
|
||||
&["urllib", "URLopener"],
|
||||
&["urllib", "request", "URLopener"],
|
||||
&["urllib", "FancyURLopener"],
|
||||
&["urllib", "request", "FancyURLopener"],
|
||||
&["urllib2", "urlopen"],
|
||||
&["urllib2", "Request"],
|
||||
&["six", "moves", "urllib", "request", "urlopen"],
|
||||
&["six", "moves", "urllib", "request", "urlretrieve"],
|
||||
&["six", "moves", "urllib", "request", "URLopener"],
|
||||
&["six", "moves", "urllib", "request", "FancyURLopener"],
|
||||
],
|
||||
Reason::URLOpen,
|
||||
),
|
||||
SuspiciousMembers::new(
|
||||
&[
|
||||
&["random", "random"],
|
||||
&["random", "randrange"],
|
||||
&["random", "randint"],
|
||||
&["random", "choice"],
|
||||
&["random", "choices"],
|
||||
&["random", "uniform"],
|
||||
&["random", "triangular"],
|
||||
],
|
||||
Reason::NonCryptographicRandom,
|
||||
),
|
||||
SuspiciousMembers::new(
|
||||
&[&["ssl", "_create_unverified_context"]],
|
||||
Reason::UnverifiedContext,
|
||||
),
|
||||
SuspiciousMembers::new(
|
||||
&[
|
||||
&["xml", "etree", "cElementTree", "parse"],
|
||||
&["xml", "etree", "cElementTree", "iterparse"],
|
||||
&["xml", "etree", "cElementTree", "fromstring"],
|
||||
&["xml", "etree", "cElementTree", "XMLParser"],
|
||||
],
|
||||
Reason::XMLCElementTree,
|
||||
),
|
||||
SuspiciousMembers::new(
|
||||
&[
|
||||
&["xml", "etree", "ElementTree", "parse"],
|
||||
&["xml", "etree", "ElementTree", "iterparse"],
|
||||
&["xml", "etree", "ElementTree", "fromstring"],
|
||||
&["xml", "etree", "ElementTree", "XMLParser"],
|
||||
],
|
||||
Reason::XMLElementTree,
|
||||
),
|
||||
SuspiciousMembers::new(
|
||||
&[&["xml", "sax", "expatreader", "create_parser"]],
|
||||
Reason::XMLExpatReader,
|
||||
),
|
||||
SuspiciousMembers::new(
|
||||
&[
|
||||
&["xml", "dom", "expatbuilder", "parse"],
|
||||
&["xml", "dom", "expatbuilder", "parseString"],
|
||||
],
|
||||
Reason::XMLExpatBuilder,
|
||||
),
|
||||
SuspiciousMembers::new(
|
||||
&[
|
||||
&["xml", "sax", "parse"],
|
||||
&["xml", "sax", "parseString"],
|
||||
&["xml", "sax", "make_parser"],
|
||||
],
|
||||
Reason::XMLSax,
|
||||
),
|
||||
SuspiciousMembers::new(
|
||||
&[
|
||||
&["xml", "dom", "minidom", "parse"],
|
||||
&["xml", "dom", "minidom", "parseString"],
|
||||
],
|
||||
Reason::XMLMiniDOM,
|
||||
),
|
||||
SuspiciousMembers::new(
|
||||
&[
|
||||
&["xml", "dom", "pulldom", "parse"],
|
||||
&["xml", "dom", "pulldom", "parseString"],
|
||||
],
|
||||
Reason::XMLPullDOM,
|
||||
),
|
||||
SuspiciousMembers::new(
|
||||
&[
|
||||
&["lxml", "etree", "parse"],
|
||||
&["lxml", "etree", "fromstring"],
|
||||
&["lxml", "etree", "RestrictedElement"],
|
||||
&["lxml", "etree", "GlobalParserTLS"],
|
||||
&["lxml", "etree", "getDefaultParser"],
|
||||
&["lxml", "etree", "check_docinfo"],
|
||||
],
|
||||
Reason::XMLETree,
|
||||
),
|
||||
];
|
||||
|
||||
const SUSPICIOUS_MODULES: &[SuspiciousModule] = &[
|
||||
SuspiciousModule::new("telnetlib", Reason::Telnet),
|
||||
SuspiciousModule::new("ftplib", Reason::FTPLib),
|
||||
];
|
||||
|
||||
/// S001
|
||||
pub fn suspicious_function_call(checker: &mut Checker, expr: &Expr) {
|
||||
let ExprKind::Call { func, .. } = &expr.node else {
|
||||
return;
|
||||
};
|
||||
|
||||
let Some(reason) = checker.ctx.resolve_call_path(func).and_then(|call_path| {
|
||||
for module in SUSPICIOUS_MEMBERS {
|
||||
for member in module.members {
|
||||
if call_path.as_slice() == *member {
|
||||
return Some(module.reason);
|
||||
}
|
||||
}
|
||||
}
|
||||
for module in SUSPICIOUS_MODULES {
|
||||
if call_path.first() == Some(&module.name) {
|
||||
return Some(module.reason);
|
||||
}
|
||||
}
|
||||
None
|
||||
}) else {
|
||||
return;
|
||||
};
|
||||
|
||||
let diagnostic_kind = match reason {
|
||||
Reason::Pickle => SuspiciousPickleUsage.into(),
|
||||
Reason::Marshal => SuspiciousMarshalUsage.into(),
|
||||
Reason::InsecureHash => SuspiciousInsecureHashUsage.into(),
|
||||
Reason::InsecureCipher => SuspiciousInsecureCipherUsage.into(),
|
||||
Reason::InsecureCipherMode => SuspiciousInsecureCipherModeUsage.into(),
|
||||
Reason::Mktemp => SuspiciousMktempUsage.into(),
|
||||
Reason::Eval => SuspiciousEvalUsage.into(),
|
||||
Reason::MarkSafe => SuspiciousMarkSafeUsage.into(),
|
||||
Reason::URLOpen => SuspiciousURLOpenUsage.into(),
|
||||
Reason::NonCryptographicRandom => SuspiciousNonCryptographicRandomUsage.into(),
|
||||
Reason::XMLCElementTree => SuspiciousXMLCElementTreeUsage.into(),
|
||||
Reason::XMLElementTree => SuspiciousXMLElementTreeUsage.into(),
|
||||
Reason::XMLExpatReader => SuspiciousXMLExpatReaderUsage.into(),
|
||||
Reason::XMLExpatBuilder => SuspiciousXMLExpatBuilderUsage.into(),
|
||||
Reason::XMLSax => SuspiciousXMLSaxUsage.into(),
|
||||
Reason::XMLMiniDOM => SuspiciousXMLMiniDOMUsage.into(),
|
||||
Reason::XMLPullDOM => SuspiciousXMLPullDOMUsage.into(),
|
||||
Reason::XMLETree => SuspiciousXMLETreeUsage.into(),
|
||||
Reason::UnverifiedContext => SuspiciousUnverifiedContextUsage.into(),
|
||||
Reason::Telnet => SuspiciousTelnetUsage.into(),
|
||||
Reason::FTPLib => SuspiciousFTPLibUsage.into(),
|
||||
};
|
||||
let diagnostic = Diagnostic::new::<DiagnosticKind>(diagnostic_kind, Range::from(expr));
|
||||
if checker.settings.rules.enabled(diagnostic.kind.rule()) {
|
||||
checker.diagnostics.push(diagnostic);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
---
|
||||
source: crates/ruff/src/rules/flake8_bandit/mod.rs
|
||||
expression: diagnostics
|
||||
---
|
||||
- kind:
|
||||
name: SuspiciousPickleUsage
|
||||
body: "`pickle` and modules that wrap it can be unsafe when used to deserialize untrusted data, possible security issue"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
location:
|
||||
row: 3
|
||||
column: 0
|
||||
end_location:
|
||||
row: 3
|
||||
column: 14
|
||||
fix: ~
|
||||
parent: ~
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
---
|
||||
source: crates/ruff/src/rules/flake8_bandit/mod.rs
|
||||
expression: diagnostics
|
||||
---
|
||||
- kind:
|
||||
name: SuspiciousTelnetUsage
|
||||
body: Telnet-related functions are being called. Telnet is considered insecure. Use SSH or some other encrypted protocol.
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
location:
|
||||
row: 3
|
||||
column: 0
|
||||
end_location:
|
||||
row: 3
|
||||
column: 23
|
||||
fix: ~
|
||||
parent: ~
|
||||
|
||||
@@ -20,7 +20,7 @@ mod tests {
|
||||
#[test_case(Rule::StripWithMultiCharacters, Path::new("B005.py"); "B005")]
|
||||
#[test_case(Rule::MutableArgumentDefault, Path::new("B006_B008.py"); "B006")]
|
||||
#[test_case(Rule::UnusedLoopControlVariable, Path::new("B007.py"); "B007")]
|
||||
#[test_case(Rule::FunctionCallArgumentDefault, Path::new("B006_B008.py"); "B008")]
|
||||
#[test_case(Rule::FunctionCallInDefaultArgument, Path::new("B006_B008.py"); "B008")]
|
||||
#[test_case(Rule::GetAttrWithConstant, Path::new("B009_B010.py"); "B009")]
|
||||
#[test_case(Rule::SetAttrWithConstant, Path::new("B009_B010.py"); "B010")]
|
||||
#[test_case(Rule::AssertFalse, Path::new("B011.py"); "B011")]
|
||||
@@ -69,7 +69,7 @@ mod tests {
|
||||
"fastapi.Query".to_string(),
|
||||
],
|
||||
},
|
||||
..Settings::for_rules(vec![Rule::FunctionCallArgumentDefault])
|
||||
..Settings::for_rules(vec![Rule::FunctionCallInDefaultArgument])
|
||||
},
|
||||
)?;
|
||||
assert_yaml_snapshot!(snapshot, diagnostics);
|
||||
|
||||
@@ -13,14 +13,14 @@ use crate::checkers::ast::Checker;
|
||||
use super::mutable_argument_default::is_mutable_func;
|
||||
|
||||
#[violation]
|
||||
pub struct FunctionCallArgumentDefault {
|
||||
pub struct FunctionCallInDefaultArgument {
|
||||
pub name: Option<String>,
|
||||
}
|
||||
|
||||
impl Violation for FunctionCallArgumentDefault {
|
||||
impl Violation for FunctionCallInDefaultArgument {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
let FunctionCallArgumentDefault { name } = self;
|
||||
let FunctionCallInDefaultArgument { name } = self;
|
||||
if let Some(name) = name {
|
||||
format!("Do not perform function call `{name}` in argument defaults")
|
||||
} else {
|
||||
@@ -71,7 +71,7 @@ where
|
||||
&& !is_nan_or_infinity(func, args)
|
||||
{
|
||||
self.diagnostics.push((
|
||||
FunctionCallArgumentDefault {
|
||||
FunctionCallInDefaultArgument {
|
||||
name: compose_call_path(func),
|
||||
}
|
||||
.into(),
|
||||
|
||||
@@ -16,7 +16,7 @@ pub use except_with_non_exception_classes::{
|
||||
};
|
||||
pub use f_string_docstring::{f_string_docstring, FStringDocstring};
|
||||
pub use function_call_argument_default::{
|
||||
function_call_argument_default, FunctionCallArgumentDefault,
|
||||
function_call_argument_default, FunctionCallInDefaultArgument,
|
||||
};
|
||||
pub use function_uses_loop_variable::{function_uses_loop_variable, FunctionUsesLoopVariable};
|
||||
pub use getattr_with_constant::{getattr_with_constant, GetAttrWithConstant};
|
||||
|
||||
@@ -22,7 +22,7 @@ use rustc_hash::FxHashMap;
|
||||
use rustpython_parser::ast::{Expr, ExprKind, Stmt};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use ruff_diagnostics::{AutofixKind, Availability, Diagnostic, Fix, Violation};
|
||||
use ruff_diagnostics::{AutofixKind, Diagnostic, Fix, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::types::{Range, RefEquality};
|
||||
use ruff_python_ast::visitor::Visitor;
|
||||
@@ -52,7 +52,7 @@ pub struct UnusedLoopControlVariable {
|
||||
}
|
||||
|
||||
impl Violation for UnusedLoopControlVariable {
|
||||
const AUTOFIX: Option<AutofixKind> = Some(AutofixKind::new(Availability::Sometimes));
|
||||
const AUTOFIX: AutofixKind = AutofixKind::Sometimes;
|
||||
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
|
||||
@@ -3,7 +3,7 @@ source: crates/ruff/src/rules/flake8_bugbear/mod.rs
|
||||
expression: diagnostics
|
||||
---
|
||||
- kind:
|
||||
name: FunctionCallArgumentDefault
|
||||
name: FunctionCallInDefaultArgument
|
||||
body: "Do not perform function call `range` in argument defaults"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
@@ -16,7 +16,7 @@ expression: diagnostics
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
name: FunctionCallArgumentDefault
|
||||
name: FunctionCallInDefaultArgument
|
||||
body: "Do not perform function call `range` in argument defaults"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
@@ -29,7 +29,7 @@ expression: diagnostics
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
name: FunctionCallArgumentDefault
|
||||
name: FunctionCallInDefaultArgument
|
||||
body: "Do not perform function call `range` in argument defaults"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
@@ -42,7 +42,7 @@ expression: diagnostics
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
name: FunctionCallArgumentDefault
|
||||
name: FunctionCallInDefaultArgument
|
||||
body: "Do not perform function call `time.time` in argument defaults"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
@@ -55,7 +55,7 @@ expression: diagnostics
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
name: FunctionCallArgumentDefault
|
||||
name: FunctionCallInDefaultArgument
|
||||
body: "Do not perform function call `dt.datetime.now` in argument defaults"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
@@ -68,7 +68,7 @@ expression: diagnostics
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
name: FunctionCallArgumentDefault
|
||||
name: FunctionCallInDefaultArgument
|
||||
body: "Do not perform function call `dt.timedelta` in argument defaults"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
@@ -81,7 +81,7 @@ expression: diagnostics
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
name: FunctionCallArgumentDefault
|
||||
name: FunctionCallInDefaultArgument
|
||||
body: Do not perform function call in argument defaults
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
@@ -94,7 +94,7 @@ expression: diagnostics
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
name: FunctionCallArgumentDefault
|
||||
name: FunctionCallInDefaultArgument
|
||||
body: "Do not perform function call `float` in argument defaults"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
@@ -107,7 +107,7 @@ expression: diagnostics
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
name: FunctionCallArgumentDefault
|
||||
name: FunctionCallInDefaultArgument
|
||||
body: "Do not perform function call `float` in argument defaults"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
@@ -120,7 +120,7 @@ expression: diagnostics
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
name: FunctionCallArgumentDefault
|
||||
name: FunctionCallInDefaultArgument
|
||||
body: "Do not perform function call `float` in argument defaults"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
@@ -133,7 +133,7 @@ expression: diagnostics
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
name: FunctionCallArgumentDefault
|
||||
name: FunctionCallInDefaultArgument
|
||||
body: "Do not perform function call `float` in argument defaults"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
@@ -146,7 +146,7 @@ expression: diagnostics
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
name: FunctionCallArgumentDefault
|
||||
name: FunctionCallInDefaultArgument
|
||||
body: "Do not perform function call `dt.datetime.now` in argument defaults"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
@@ -159,7 +159,7 @@ expression: diagnostics
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
name: FunctionCallArgumentDefault
|
||||
name: FunctionCallInDefaultArgument
|
||||
body: "Do not perform function call `map` in argument defaults"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
@@ -172,7 +172,7 @@ expression: diagnostics
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
name: FunctionCallArgumentDefault
|
||||
name: FunctionCallInDefaultArgument
|
||||
body: "Do not perform function call `random.randint` in argument defaults"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
@@ -185,7 +185,7 @@ expression: diagnostics
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
name: FunctionCallArgumentDefault
|
||||
name: FunctionCallInDefaultArgument
|
||||
body: "Do not perform function call `dt.datetime.now` in argument defaults"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
|
||||
@@ -3,7 +3,7 @@ source: crates/ruff/src/rules/flake8_bugbear/mod.rs
|
||||
expression: diagnostics
|
||||
---
|
||||
- kind:
|
||||
name: FunctionCallArgumentDefault
|
||||
name: FunctionCallInDefaultArgument
|
||||
body: "Do not perform function call `Depends` in argument defaults"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
|
||||
@@ -19,9 +19,9 @@ mod tests {
|
||||
let diagnostics = test_path(
|
||||
Path::new("flake8_commas").join(path).as_path(),
|
||||
&settings::Settings::for_rules(vec![
|
||||
Rule::TrailingCommaMissing,
|
||||
Rule::TrailingCommaOnBareTupleProhibited,
|
||||
Rule::TrailingCommaProhibited,
|
||||
Rule::MissingTrailingComma,
|
||||
Rule::TrailingCommaOnBareTuple,
|
||||
Rule::ProhibitedTrailingComma,
|
||||
]),
|
||||
)?;
|
||||
assert_yaml_snapshot!(snapshot, diagnostics);
|
||||
|
||||
@@ -111,9 +111,9 @@ impl Context {
|
||||
}
|
||||
|
||||
#[violation]
|
||||
pub struct TrailingCommaMissing;
|
||||
pub struct MissingTrailingComma;
|
||||
|
||||
impl AlwaysAutofixableViolation for TrailingCommaMissing {
|
||||
impl AlwaysAutofixableViolation for MissingTrailingComma {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!("Trailing comma missing")
|
||||
@@ -125,9 +125,9 @@ impl AlwaysAutofixableViolation for TrailingCommaMissing {
|
||||
}
|
||||
|
||||
#[violation]
|
||||
pub struct TrailingCommaOnBareTupleProhibited;
|
||||
pub struct TrailingCommaOnBareTuple;
|
||||
|
||||
impl Violation for TrailingCommaOnBareTupleProhibited {
|
||||
impl Violation for TrailingCommaOnBareTuple {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!("Trailing comma on bare tuple prohibited")
|
||||
@@ -135,9 +135,9 @@ impl Violation for TrailingCommaOnBareTupleProhibited {
|
||||
}
|
||||
|
||||
#[violation]
|
||||
pub struct TrailingCommaProhibited;
|
||||
pub struct ProhibitedTrailingComma;
|
||||
|
||||
impl AlwaysAutofixableViolation for TrailingCommaProhibited {
|
||||
impl AlwaysAutofixableViolation for ProhibitedTrailingComma {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!("Trailing comma prohibited")
|
||||
@@ -254,13 +254,13 @@ pub fn trailing_commas(
|
||||
if comma_prohibited {
|
||||
let comma = prev.spanned.unwrap();
|
||||
let mut diagnostic = Diagnostic::new(
|
||||
TrailingCommaProhibited,
|
||||
ProhibitedTrailingComma,
|
||||
Range {
|
||||
location: comma.0,
|
||||
end_location: comma.2,
|
||||
},
|
||||
);
|
||||
if autofix.into() && settings.rules.should_fix(Rule::TrailingCommaProhibited) {
|
||||
if autofix.into() && settings.rules.should_fix(Rule::ProhibitedTrailingComma) {
|
||||
diagnostic.amend(Fix::deletion(comma.0, comma.2));
|
||||
}
|
||||
diagnostics.push(diagnostic);
|
||||
@@ -273,7 +273,7 @@ pub fn trailing_commas(
|
||||
if bare_comma_prohibited {
|
||||
let comma = prev.spanned.unwrap();
|
||||
diagnostics.push(Diagnostic::new(
|
||||
TrailingCommaOnBareTupleProhibited,
|
||||
TrailingCommaOnBareTuple,
|
||||
Range {
|
||||
location: comma.0,
|
||||
end_location: comma.2,
|
||||
@@ -298,13 +298,13 @@ pub fn trailing_commas(
|
||||
if comma_required {
|
||||
let missing_comma = prev_prev.spanned.unwrap();
|
||||
let mut diagnostic = Diagnostic::new(
|
||||
TrailingCommaMissing,
|
||||
MissingTrailingComma,
|
||||
Range {
|
||||
location: missing_comma.2,
|
||||
end_location: missing_comma.2,
|
||||
},
|
||||
);
|
||||
if autofix.into() && settings.rules.should_fix(Rule::TrailingCommaMissing) {
|
||||
if autofix.into() && settings.rules.should_fix(Rule::MissingTrailingComma) {
|
||||
// Create a replacement that includes the final bracket (or other token),
|
||||
// rather than just inserting a comma at the end. This prevents the UP034 autofix
|
||||
// removing any brackets in the same linter pass - doing both at the same time could
|
||||
|
||||
@@ -3,7 +3,7 @@ source: crates/ruff/src/rules/flake8_commas/mod.rs
|
||||
expression: diagnostics
|
||||
---
|
||||
- kind:
|
||||
name: TrailingCommaMissing
|
||||
name: MissingTrailingComma
|
||||
body: Trailing comma missing
|
||||
suggestion: Add trailing comma
|
||||
fixable: true
|
||||
@@ -23,7 +23,7 @@ expression: diagnostics
|
||||
column: 17
|
||||
parent: ~
|
||||
- kind:
|
||||
name: TrailingCommaMissing
|
||||
name: MissingTrailingComma
|
||||
body: Trailing comma missing
|
||||
suggestion: Add trailing comma
|
||||
fixable: true
|
||||
@@ -43,7 +43,7 @@ expression: diagnostics
|
||||
column: 5
|
||||
parent: ~
|
||||
- kind:
|
||||
name: TrailingCommaMissing
|
||||
name: MissingTrailingComma
|
||||
body: Trailing comma missing
|
||||
suggestion: Add trailing comma
|
||||
fixable: true
|
||||
@@ -63,7 +63,7 @@ expression: diagnostics
|
||||
column: 5
|
||||
parent: ~
|
||||
- kind:
|
||||
name: TrailingCommaMissing
|
||||
name: MissingTrailingComma
|
||||
body: Trailing comma missing
|
||||
suggestion: Add trailing comma
|
||||
fixable: true
|
||||
@@ -83,7 +83,7 @@ expression: diagnostics
|
||||
column: 5
|
||||
parent: ~
|
||||
- kind:
|
||||
name: TrailingCommaOnBareTupleProhibited
|
||||
name: TrailingCommaOnBareTuple
|
||||
body: Trailing comma on bare tuple prohibited
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
@@ -96,7 +96,7 @@ expression: diagnostics
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
name: TrailingCommaOnBareTupleProhibited
|
||||
name: TrailingCommaOnBareTuple
|
||||
body: Trailing comma on bare tuple prohibited
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
@@ -109,7 +109,7 @@ expression: diagnostics
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
name: TrailingCommaOnBareTupleProhibited
|
||||
name: TrailingCommaOnBareTuple
|
||||
body: Trailing comma on bare tuple prohibited
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
@@ -122,7 +122,7 @@ expression: diagnostics
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
name: TrailingCommaOnBareTupleProhibited
|
||||
name: TrailingCommaOnBareTuple
|
||||
body: Trailing comma on bare tuple prohibited
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
@@ -135,7 +135,7 @@ expression: diagnostics
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
name: TrailingCommaOnBareTupleProhibited
|
||||
name: TrailingCommaOnBareTuple
|
||||
body: Trailing comma on bare tuple prohibited
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
@@ -148,7 +148,7 @@ expression: diagnostics
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
name: TrailingCommaOnBareTupleProhibited
|
||||
name: TrailingCommaOnBareTuple
|
||||
body: Trailing comma on bare tuple prohibited
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
@@ -161,7 +161,7 @@ expression: diagnostics
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
name: TrailingCommaOnBareTupleProhibited
|
||||
name: TrailingCommaOnBareTuple
|
||||
body: Trailing comma on bare tuple prohibited
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
@@ -174,7 +174,7 @@ expression: diagnostics
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
name: TrailingCommaMissing
|
||||
name: MissingTrailingComma
|
||||
body: Trailing comma missing
|
||||
suggestion: Add trailing comma
|
||||
fixable: true
|
||||
@@ -194,7 +194,7 @@ expression: diagnostics
|
||||
column: 7
|
||||
parent: ~
|
||||
- kind:
|
||||
name: TrailingCommaMissing
|
||||
name: MissingTrailingComma
|
||||
body: Trailing comma missing
|
||||
suggestion: Add trailing comma
|
||||
fixable: true
|
||||
@@ -214,7 +214,7 @@ expression: diagnostics
|
||||
column: 7
|
||||
parent: ~
|
||||
- kind:
|
||||
name: TrailingCommaMissing
|
||||
name: MissingTrailingComma
|
||||
body: Trailing comma missing
|
||||
suggestion: Add trailing comma
|
||||
fixable: true
|
||||
@@ -234,7 +234,7 @@ expression: diagnostics
|
||||
column: 7
|
||||
parent: ~
|
||||
- kind:
|
||||
name: TrailingCommaMissing
|
||||
name: MissingTrailingComma
|
||||
body: Trailing comma missing
|
||||
suggestion: Add trailing comma
|
||||
fixable: true
|
||||
@@ -254,7 +254,7 @@ expression: diagnostics
|
||||
column: 5
|
||||
parent: ~
|
||||
- kind:
|
||||
name: TrailingCommaMissing
|
||||
name: MissingTrailingComma
|
||||
body: Trailing comma missing
|
||||
suggestion: Add trailing comma
|
||||
fixable: true
|
||||
@@ -274,7 +274,7 @@ expression: diagnostics
|
||||
column: 10
|
||||
parent: ~
|
||||
- kind:
|
||||
name: TrailingCommaMissing
|
||||
name: MissingTrailingComma
|
||||
body: Trailing comma missing
|
||||
suggestion: Add trailing comma
|
||||
fixable: true
|
||||
@@ -294,7 +294,7 @@ expression: diagnostics
|
||||
column: 14
|
||||
parent: ~
|
||||
- kind:
|
||||
name: TrailingCommaMissing
|
||||
name: MissingTrailingComma
|
||||
body: Trailing comma missing
|
||||
suggestion: Add trailing comma
|
||||
fixable: true
|
||||
@@ -314,7 +314,7 @@ expression: diagnostics
|
||||
column: 13
|
||||
parent: ~
|
||||
- kind:
|
||||
name: TrailingCommaMissing
|
||||
name: MissingTrailingComma
|
||||
body: Trailing comma missing
|
||||
suggestion: Add trailing comma
|
||||
fixable: true
|
||||
@@ -334,7 +334,7 @@ expression: diagnostics
|
||||
column: 13
|
||||
parent: ~
|
||||
- kind:
|
||||
name: TrailingCommaMissing
|
||||
name: MissingTrailingComma
|
||||
body: Trailing comma missing
|
||||
suggestion: Add trailing comma
|
||||
fixable: true
|
||||
@@ -354,7 +354,7 @@ expression: diagnostics
|
||||
column: 9
|
||||
parent: ~
|
||||
- kind:
|
||||
name: TrailingCommaMissing
|
||||
name: MissingTrailingComma
|
||||
body: Trailing comma missing
|
||||
suggestion: Add trailing comma
|
||||
fixable: true
|
||||
@@ -374,7 +374,7 @@ expression: diagnostics
|
||||
column: 14
|
||||
parent: ~
|
||||
- kind:
|
||||
name: TrailingCommaMissing
|
||||
name: MissingTrailingComma
|
||||
body: Trailing comma missing
|
||||
suggestion: Add trailing comma
|
||||
fixable: true
|
||||
@@ -394,7 +394,7 @@ expression: diagnostics
|
||||
column: 14
|
||||
parent: ~
|
||||
- kind:
|
||||
name: TrailingCommaMissing
|
||||
name: MissingTrailingComma
|
||||
body: Trailing comma missing
|
||||
suggestion: Add trailing comma
|
||||
fixable: true
|
||||
@@ -414,7 +414,7 @@ expression: diagnostics
|
||||
column: 14
|
||||
parent: ~
|
||||
- kind:
|
||||
name: TrailingCommaMissing
|
||||
name: MissingTrailingComma
|
||||
body: Trailing comma missing
|
||||
suggestion: Add trailing comma
|
||||
fixable: true
|
||||
@@ -434,7 +434,7 @@ expression: diagnostics
|
||||
column: 14
|
||||
parent: ~
|
||||
- kind:
|
||||
name: TrailingCommaMissing
|
||||
name: MissingTrailingComma
|
||||
body: Trailing comma missing
|
||||
suggestion: Add trailing comma
|
||||
fixable: true
|
||||
@@ -454,7 +454,7 @@ expression: diagnostics
|
||||
column: 14
|
||||
parent: ~
|
||||
- kind:
|
||||
name: TrailingCommaProhibited
|
||||
name: ProhibitedTrailingComma
|
||||
body: Trailing comma prohibited
|
||||
suggestion: Remove trailing comma
|
||||
fixable: true
|
||||
@@ -474,7 +474,7 @@ expression: diagnostics
|
||||
column: 21
|
||||
parent: ~
|
||||
- kind:
|
||||
name: TrailingCommaProhibited
|
||||
name: ProhibitedTrailingComma
|
||||
body: Trailing comma prohibited
|
||||
suggestion: Remove trailing comma
|
||||
fixable: true
|
||||
@@ -494,7 +494,7 @@ expression: diagnostics
|
||||
column: 13
|
||||
parent: ~
|
||||
- kind:
|
||||
name: TrailingCommaProhibited
|
||||
name: ProhibitedTrailingComma
|
||||
body: Trailing comma prohibited
|
||||
suggestion: Remove trailing comma
|
||||
fixable: true
|
||||
@@ -514,7 +514,7 @@ expression: diagnostics
|
||||
column: 18
|
||||
parent: ~
|
||||
- kind:
|
||||
name: TrailingCommaProhibited
|
||||
name: ProhibitedTrailingComma
|
||||
body: Trailing comma prohibited
|
||||
suggestion: Remove trailing comma
|
||||
fixable: true
|
||||
@@ -534,7 +534,7 @@ expression: diagnostics
|
||||
column: 6
|
||||
parent: ~
|
||||
- kind:
|
||||
name: TrailingCommaProhibited
|
||||
name: ProhibitedTrailingComma
|
||||
body: Trailing comma prohibited
|
||||
suggestion: Remove trailing comma
|
||||
fixable: true
|
||||
@@ -554,7 +554,7 @@ expression: diagnostics
|
||||
column: 21
|
||||
parent: ~
|
||||
- kind:
|
||||
name: TrailingCommaProhibited
|
||||
name: ProhibitedTrailingComma
|
||||
body: Trailing comma prohibited
|
||||
suggestion: Remove trailing comma
|
||||
fixable: true
|
||||
@@ -574,7 +574,7 @@ expression: diagnostics
|
||||
column: 13
|
||||
parent: ~
|
||||
- kind:
|
||||
name: TrailingCommaProhibited
|
||||
name: ProhibitedTrailingComma
|
||||
body: Trailing comma prohibited
|
||||
suggestion: Remove trailing comma
|
||||
fixable: true
|
||||
@@ -594,7 +594,7 @@ expression: diagnostics
|
||||
column: 18
|
||||
parent: ~
|
||||
- kind:
|
||||
name: TrailingCommaProhibited
|
||||
name: ProhibitedTrailingComma
|
||||
body: Trailing comma prohibited
|
||||
suggestion: Remove trailing comma
|
||||
fixable: true
|
||||
@@ -614,7 +614,7 @@ expression: diagnostics
|
||||
column: 6
|
||||
parent: ~
|
||||
- kind:
|
||||
name: TrailingCommaProhibited
|
||||
name: ProhibitedTrailingComma
|
||||
body: Trailing comma prohibited
|
||||
suggestion: Remove trailing comma
|
||||
fixable: true
|
||||
@@ -634,7 +634,7 @@ expression: diagnostics
|
||||
column: 10
|
||||
parent: ~
|
||||
- kind:
|
||||
name: TrailingCommaProhibited
|
||||
name: ProhibitedTrailingComma
|
||||
body: Trailing comma prohibited
|
||||
suggestion: Remove trailing comma
|
||||
fixable: true
|
||||
@@ -654,7 +654,7 @@ expression: diagnostics
|
||||
column: 9
|
||||
parent: ~
|
||||
- kind:
|
||||
name: TrailingCommaMissing
|
||||
name: MissingTrailingComma
|
||||
body: Trailing comma missing
|
||||
suggestion: Add trailing comma
|
||||
fixable: true
|
||||
@@ -674,7 +674,7 @@ expression: diagnostics
|
||||
column: 12
|
||||
parent: ~
|
||||
- kind:
|
||||
name: TrailingCommaMissing
|
||||
name: MissingTrailingComma
|
||||
body: Trailing comma missing
|
||||
suggestion: Add trailing comma
|
||||
fixable: true
|
||||
@@ -694,7 +694,7 @@ expression: diagnostics
|
||||
column: 9
|
||||
parent: ~
|
||||
- kind:
|
||||
name: TrailingCommaMissing
|
||||
name: MissingTrailingComma
|
||||
body: Trailing comma missing
|
||||
suggestion: Add trailing comma
|
||||
fixable: true
|
||||
@@ -714,7 +714,7 @@ expression: diagnostics
|
||||
column: 15
|
||||
parent: ~
|
||||
- kind:
|
||||
name: TrailingCommaMissing
|
||||
name: MissingTrailingComma
|
||||
body: Trailing comma missing
|
||||
suggestion: Add trailing comma
|
||||
fixable: true
|
||||
@@ -734,7 +734,7 @@ expression: diagnostics
|
||||
column: 12
|
||||
parent: ~
|
||||
- kind:
|
||||
name: TrailingCommaMissing
|
||||
name: MissingTrailingComma
|
||||
body: Trailing comma missing
|
||||
suggestion: Add trailing comma
|
||||
fixable: true
|
||||
@@ -754,7 +754,7 @@ expression: diagnostics
|
||||
column: 23
|
||||
parent: ~
|
||||
- kind:
|
||||
name: TrailingCommaMissing
|
||||
name: MissingTrailingComma
|
||||
body: Trailing comma missing
|
||||
suggestion: Add trailing comma
|
||||
fixable: true
|
||||
@@ -774,7 +774,7 @@ expression: diagnostics
|
||||
column: 14
|
||||
parent: ~
|
||||
- kind:
|
||||
name: TrailingCommaMissing
|
||||
name: MissingTrailingComma
|
||||
body: Trailing comma missing
|
||||
suggestion: Add trailing comma
|
||||
fixable: true
|
||||
@@ -794,7 +794,7 @@ expression: diagnostics
|
||||
column: 12
|
||||
parent: ~
|
||||
- kind:
|
||||
name: TrailingCommaMissing
|
||||
name: MissingTrailingComma
|
||||
body: Trailing comma missing
|
||||
suggestion: Add trailing comma
|
||||
fixable: true
|
||||
@@ -814,7 +814,7 @@ expression: diagnostics
|
||||
column: 12
|
||||
parent: ~
|
||||
- kind:
|
||||
name: TrailingCommaMissing
|
||||
name: MissingTrailingComma
|
||||
body: Trailing comma missing
|
||||
suggestion: Add trailing comma
|
||||
fixable: true
|
||||
@@ -834,7 +834,7 @@ expression: diagnostics
|
||||
column: 9
|
||||
parent: ~
|
||||
- kind:
|
||||
name: TrailingCommaMissing
|
||||
name: MissingTrailingComma
|
||||
body: Trailing comma missing
|
||||
suggestion: Add trailing comma
|
||||
fixable: true
|
||||
@@ -854,7 +854,7 @@ expression: diagnostics
|
||||
column: 9
|
||||
parent: ~
|
||||
- kind:
|
||||
name: TrailingCommaMissing
|
||||
name: MissingTrailingComma
|
||||
body: Trailing comma missing
|
||||
suggestion: Add trailing comma
|
||||
fixable: true
|
||||
@@ -874,7 +874,7 @@ expression: diagnostics
|
||||
column: 9
|
||||
parent: ~
|
||||
- kind:
|
||||
name: TrailingCommaMissing
|
||||
name: MissingTrailingComma
|
||||
body: Trailing comma missing
|
||||
suggestion: Add trailing comma
|
||||
fixable: true
|
||||
@@ -894,7 +894,7 @@ expression: diagnostics
|
||||
column: 12
|
||||
parent: ~
|
||||
- kind:
|
||||
name: TrailingCommaMissing
|
||||
name: MissingTrailingComma
|
||||
body: Trailing comma missing
|
||||
suggestion: Add trailing comma
|
||||
fixable: true
|
||||
@@ -914,7 +914,7 @@ expression: diagnostics
|
||||
column: 14
|
||||
parent: ~
|
||||
- kind:
|
||||
name: TrailingCommaMissing
|
||||
name: MissingTrailingComma
|
||||
body: Trailing comma missing
|
||||
suggestion: Add trailing comma
|
||||
fixable: true
|
||||
@@ -934,7 +934,7 @@ expression: diagnostics
|
||||
column: 19
|
||||
parent: ~
|
||||
- kind:
|
||||
name: TrailingCommaMissing
|
||||
name: MissingTrailingComma
|
||||
body: Trailing comma missing
|
||||
suggestion: Add trailing comma
|
||||
fixable: true
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user