Compare commits
29 Commits
v0.0.253
...
github-292
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6e97c9438a | ||
|
|
187104e396 | ||
|
|
ea86edf12e | ||
|
|
2558384817 | ||
|
|
3ed539d50e | ||
|
|
4a70a4c323 | ||
|
|
310f13c7db | ||
|
|
2168404fc2 | ||
|
|
a032b66c2e | ||
|
|
af5f7dbd83 | ||
|
|
8066607ea3 | ||
|
|
0ed9fccce9 | ||
|
|
074a343a63 | ||
|
|
c7e09b54b0 | ||
|
|
67d1f74587 | ||
|
|
1c79dff3bd | ||
|
|
f5f09b489b | ||
|
|
061495a9eb | ||
|
|
470e1c1754 | ||
|
|
16be691712 | ||
|
|
270015865b | ||
|
|
ccfa9d5b20 | ||
|
|
2261e194a0 | ||
|
|
cd6413ca09 | ||
|
|
c65585e14a | ||
|
|
d2a6ed7be6 | ||
|
|
16e2dae0c2 | ||
|
|
e8ba9c9e21 | ||
|
|
d285f5c90a |
2
.github/workflows/ci.yaml
vendored
2
.github/workflows/ci.yaml
vendored
@@ -29,7 +29,7 @@ jobs:
|
||||
- run: ./target/debug/ruff_dev generate-all
|
||||
- run: git diff --quiet README.md || echo "::error file=README.md::This file is outdated. Run 'cargo dev generate-all'."
|
||||
- run: git diff --quiet ruff.schema.json || echo "::error file=ruff.schema.json::This file is outdated. Run 'cargo dev generate-all'."
|
||||
- run: git diff --exit-code -- README.md ruff.schema.json
|
||||
- run: git diff --exit-code -- README.md ruff.schema.json docs
|
||||
|
||||
cargo-fmt:
|
||||
name: "cargo fmt"
|
||||
|
||||
@@ -5,6 +5,14 @@ repos:
|
||||
hooks:
|
||||
- id: validate-pyproject
|
||||
|
||||
- repo: https://github.com/executablebooks/mdformat
|
||||
rev: 0.7.16
|
||||
hooks:
|
||||
- id: mdformat
|
||||
additional_dependencies:
|
||||
- mdformat-black
|
||||
- black==23.1.0 # Must be the latest version of Black
|
||||
|
||||
- repo: https://github.com/igorshubovych/markdownlint-cli
|
||||
rev: v0.33.0
|
||||
hooks:
|
||||
|
||||
@@ -20,8 +20,7 @@ the intention of adding a stable public API in the future.
|
||||
### `select`, `extend-select`, `ignore`, and `extend-ignore` have new semantics ([#2312](https://github.com/charliermarsh/ruff/pull/2312))
|
||||
|
||||
Previously, the interplay between `select` and its related options could lead to unexpected
|
||||
behavior. For example, `ruff --select E501 --ignore ALL` and `ruff --select E501 --extend-ignore
|
||||
ALL` behaved differently. (See [#2312](https://github.com/charliermarsh/ruff/pull/2312) for more
|
||||
behavior. For example, `ruff --select E501 --ignore ALL` and `ruff --select E501 --extend-ignore ALL` behaved differently. (See [#2312](https://github.com/charliermarsh/ruff/pull/2312) for more
|
||||
examples.)
|
||||
|
||||
When Ruff determines the enabled rule set, it has to reconcile `select` and `ignore` from a variety
|
||||
@@ -74,7 +73,7 @@ ruff rule E402 --format json # Works! (And preferred.)
|
||||
This change is largely backwards compatible -- most users should experience
|
||||
no change in behavior. However, please note the following exceptions:
|
||||
|
||||
* Subcommands will now fail when invoked with unsupported arguments, instead
|
||||
- Subcommands will now fail when invoked with unsupported arguments, instead
|
||||
of silently ignoring them. For example, the following will now fail:
|
||||
|
||||
```console
|
||||
@@ -83,16 +82,16 @@ no change in behavior. However, please note the following exceptions:
|
||||
|
||||
(the `clean` command doesn't support `--respect-gitignore`.)
|
||||
|
||||
* The semantics of `ruff <arg>` have changed slightly when `<arg>` is a valid subcommand.
|
||||
- The semantics of `ruff <arg>` have changed slightly when `<arg>` is a valid subcommand.
|
||||
For example, prior to this release, running `ruff rule` would run `ruff` over a file or
|
||||
directory called `rule`. Now, `ruff rule` would invoke the `rule` subcommand. This should
|
||||
only impact projects with files or directories named `rule`, `check`, `explain`, `clean`,
|
||||
or `generate-shell-completion`.
|
||||
|
||||
* Scripts that invoke ruff should supply `--` before any positional arguments.
|
||||
- Scripts that invoke ruff should supply `--` before any positional arguments.
|
||||
(The semantics of `ruff -- <arg>` have not changed.)
|
||||
|
||||
* `--explain` previously treated `--format grouped` as a synonym for `--format text`.
|
||||
- `--explain` previously treated `--format grouped` as a synonym for `--format text`.
|
||||
This is no longer supported; instead, use `--format text`.
|
||||
|
||||
## 0.0.226
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
# Contributor Covenant Code of Conduct
|
||||
|
||||
* [Our Pledge](#our-pledge)
|
||||
* [Our Standards](#our-standards)
|
||||
* [Enforcement Responsibilities](#enforcement-responsibilities)
|
||||
* [Scope](#scope)
|
||||
* [Enforcement](#enforcement)
|
||||
* [Enforcement Guidelines](#enforcement-guidelines)
|
||||
* [1. Correction](#1-correction)
|
||||
* [2. Warning](#2-warning)
|
||||
* [3. Temporary Ban](#3-temporary-ban)
|
||||
* [4. Permanent Ban](#4-permanent-ban)
|
||||
* [Attribution](#attribution)
|
||||
- [Our Pledge](#our-pledge)
|
||||
- [Our Standards](#our-standards)
|
||||
- [Enforcement Responsibilities](#enforcement-responsibilities)
|
||||
- [Scope](#scope)
|
||||
- [Enforcement](#enforcement)
|
||||
- [Enforcement Guidelines](#enforcement-guidelines)
|
||||
- [1. Correction](#1-correction)
|
||||
- [2. Warning](#2-warning)
|
||||
- [3. Temporary Ban](#3-temporary-ban)
|
||||
- [4. Permanent Ban](#4-permanent-ban)
|
||||
- [Attribution](#attribution)
|
||||
|
||||
## Our Pledge
|
||||
|
||||
@@ -29,23 +29,23 @@ diverse, inclusive, and healthy community.
|
||||
Examples of behavior that contributes to a positive environment for our
|
||||
community include:
|
||||
|
||||
* Demonstrating empathy and kindness toward other people
|
||||
* Being respectful of differing opinions, viewpoints, and experiences
|
||||
* Giving and gracefully accepting constructive feedback
|
||||
* Accepting responsibility and apologizing to those affected by our mistakes,
|
||||
- Demonstrating empathy and kindness toward other people
|
||||
- Being respectful of differing opinions, viewpoints, and experiences
|
||||
- Giving and gracefully accepting constructive feedback
|
||||
- Accepting responsibility and apologizing to those affected by our mistakes,
|
||||
and learning from the experience
|
||||
* Focusing on what is best not just for us as individuals, but for the
|
||||
- Focusing on what is best not just for us as individuals, but for the
|
||||
overall community
|
||||
|
||||
Examples of unacceptable behavior include:
|
||||
|
||||
* The use of sexualized language or imagery, and sexual attention or
|
||||
- The use of sexualized language or imagery, and sexual attention or
|
||||
advances of any kind
|
||||
* Trolling, insulting or derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or email
|
||||
- Trolling, insulting or derogatory comments, and personal or political attacks
|
||||
- Public or private harassment
|
||||
- Publishing others' private information, such as a physical or email
|
||||
address, without their explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a
|
||||
- Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
|
||||
## Enforcement Responsibilities
|
||||
@@ -132,7 +132,7 @@ version 2.0, available [here](https://www.contributor-covenant.org/version/2/0/c
|
||||
Community Impact Guidelines were inspired by [Mozilla's code of conduct
|
||||
enforcement ladder](https://github.com/mozilla/diversity).
|
||||
|
||||
[homepage]: https://www.contributor-covenant.org
|
||||
|
||||
For answers to common questions about this code of conduct, see the [FAQ](https://www.contributor-covenant.org/faq).
|
||||
Translations are available [here](https://www.contributor-covenant.org/translations).
|
||||
|
||||
[homepage]: https://www.contributor-covenant.org
|
||||
|
||||
@@ -2,16 +2,16 @@
|
||||
|
||||
Welcome! We're happy to have you here. Thank you in advance for your contribution to Ruff.
|
||||
|
||||
* [The Basics](#the-basics)
|
||||
* [Prerequisites](#prerequisites)
|
||||
* [Development](#development)
|
||||
* [Project Structure](#project-structure)
|
||||
* [Example: Adding a new lint rule](#example-adding-a-new-lint-rule)
|
||||
* [Rule naming convention](#rule-naming-convention)
|
||||
* [Example: Adding a new configuration option](#example-adding-a-new-configuration-option)
|
||||
* [MkDocs](#mkdocs)
|
||||
* [Release Process](#release-process)
|
||||
* [Benchmarks](#benchmarks)
|
||||
- [The Basics](#the-basics)
|
||||
- [Prerequisites](#prerequisites)
|
||||
- [Development](#development)
|
||||
- [Project Structure](#project-structure)
|
||||
- [Example: Adding a new lint rule](#example-adding-a-new-lint-rule)
|
||||
- [Rule naming convention](#rule-naming-convention)
|
||||
- [Example: Adding a new configuration option](#example-adding-a-new-configuration-option)
|
||||
- [MkDocs](#mkdocs)
|
||||
- [Release Process](#release-process)
|
||||
- [Benchmarks](#benchmarks)
|
||||
|
||||
## The Basics
|
||||
|
||||
@@ -91,27 +91,27 @@ The vast majority of the code, including all lint rules, lives in the `ruff` cra
|
||||
|
||||
At time of writing, the repository includes the following crates:
|
||||
|
||||
* `crates/ruff`: library crate containing all lint rules and the core logic for running them.
|
||||
* `crates/ruff_cli`: binary crate containing Ruff's command-line interface.
|
||||
* `crates/ruff_dev`: binary crate containing utilities used in the development of Ruff itself (e.g., `cargo dev generate-all`).
|
||||
* `crates/ruff_macros`: library crate containing macros used by Ruff.
|
||||
* `crates/ruff_python`: library crate implementing Python-specific functionality (e.g., lists of standard library modules by versionb).
|
||||
* `crates/flake8_to_ruff`: binary crate for generating Ruff configuration from Flake8 configuration.
|
||||
- `crates/ruff`: library crate containing all lint rules and the core logic for running them.
|
||||
- `crates/ruff_cli`: binary crate containing Ruff's command-line interface.
|
||||
- `crates/ruff_dev`: binary crate containing utilities used in the development of Ruff itself (e.g., `cargo dev generate-all`).
|
||||
- `crates/ruff_macros`: library crate containing macros used by Ruff.
|
||||
- `crates/ruff_python`: library crate implementing Python-specific functionality (e.g., lists of standard library modules by versionb).
|
||||
- `crates/flake8_to_ruff`: binary crate for generating Ruff configuration from Flake8 configuration.
|
||||
|
||||
### Example: Adding a new lint rule
|
||||
|
||||
At a high level, the steps involved in adding a new lint rule are as follows:
|
||||
|
||||
1. Determine a name for the new rule as per our [rule naming convention](#rule-naming-convention).
|
||||
2. Create a file for your rule (e.g., `crates/ruff/src/rules/flake8_bugbear/rules/abstract_base_class.rs`).
|
||||
3. In that file, define a violation struct. You can grep for `define_violation!` to see examples.
|
||||
4. Map the violation struct to a rule code in `crates/ruff/src/registry.rs` (e.g., `E402`).
|
||||
5. Define the logic for triggering the violation in `crates/ruff/src/checkers/ast.rs` (for AST-based
|
||||
1. Create a file for your rule (e.g., `crates/ruff/src/rules/flake8_bugbear/rules/abstract_base_class.rs`).
|
||||
1. In that file, define a violation struct. You can grep for `define_violation!` to see examples.
|
||||
1. Map the violation struct to a rule code in `crates/ruff/src/registry.rs` (e.g., `E402`).
|
||||
1. Define the logic for triggering the violation in `crates/ruff/src/checkers/ast.rs` (for AST-based
|
||||
checks), `crates/ruff/src/checkers/tokens.rs` (for token-based checks), `crates/ruff/src/checkers/lines.rs`
|
||||
(for text-based checks), or `crates/ruff/src/checkers/filesystem.rs` (for filesystem-based
|
||||
checks).
|
||||
6. Add a test fixture.
|
||||
7. Update the generated files (documentation and generated code).
|
||||
1. Add a test fixture.
|
||||
1. Update the generated files (documentation and generated code).
|
||||
|
||||
To define the violation, start by creating a dedicated file for your rule under the appropriate
|
||||
rule linter (e.g., `crates/ruff/src/rules/flake8_bugbear/rules/abstract_base_class.rs`). That file should
|
||||
@@ -147,9 +147,9 @@ The rule name should make sense when read as "allow _rule-name_" or "allow _rule
|
||||
|
||||
This implies that rule names:
|
||||
|
||||
* should state the bad thing being checked for
|
||||
- should state the bad thing being checked for
|
||||
|
||||
* should not contain instructions on what you what you should use instead
|
||||
- should not contain instructions on what you what you should use instead
|
||||
(these belong in the rule documentation and the `autofix_title` for rules that have autofix)
|
||||
|
||||
When re-implementing rules from other linters, this convention is given more importance than
|
||||
@@ -191,13 +191,13 @@ To preview any changes to the documentation locally:
|
||||
pip install -r docs/requirements.txt
|
||||
```
|
||||
|
||||
2. Generate the MkDocs site with:
|
||||
1. Generate the MkDocs site with:
|
||||
|
||||
```shell
|
||||
python scripts/generate_mkdocs.py
|
||||
```
|
||||
|
||||
3. Run the development server with:
|
||||
1. Run the development server with:
|
||||
|
||||
```shell
|
||||
mkdocs serve
|
||||
|
||||
17
Cargo.lock
generated
17
Cargo.lock
generated
@@ -2141,6 +2141,7 @@ dependencies = [
|
||||
"clap 4.1.6",
|
||||
"insta",
|
||||
"is-macro",
|
||||
"itertools",
|
||||
"once_cell",
|
||||
"ruff_formatter",
|
||||
"ruff_python",
|
||||
@@ -2230,7 +2231,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "rustpython-ast"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/RustPython/RustPython.git?rev=c4b67896662b16b5699a779c0e52aa0ca2587fec#c4b67896662b16b5699a779c0e52aa0ca2587fec"
|
||||
source = "git+https://github.com/RustPython/RustPython.git?rev=aa8336ee94492b52458ed8e1517238e5c6c2914c#aa8336ee94492b52458ed8e1517238e5c6c2914c"
|
||||
dependencies = [
|
||||
"num-bigint",
|
||||
"rustpython-compiler-core",
|
||||
@@ -2239,7 +2240,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "rustpython-common"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/RustPython/RustPython.git?rev=c4b67896662b16b5699a779c0e52aa0ca2587fec#c4b67896662b16b5699a779c0e52aa0ca2587fec"
|
||||
source = "git+https://github.com/RustPython/RustPython.git?rev=aa8336ee94492b52458ed8e1517238e5c6c2914c#aa8336ee94492b52458ed8e1517238e5c6c2914c"
|
||||
dependencies = [
|
||||
"ascii",
|
||||
"bitflags",
|
||||
@@ -2264,7 +2265,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "rustpython-compiler-core"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/RustPython/RustPython.git?rev=c4b67896662b16b5699a779c0e52aa0ca2587fec#c4b67896662b16b5699a779c0e52aa0ca2587fec"
|
||||
source = "git+https://github.com/RustPython/RustPython.git?rev=aa8336ee94492b52458ed8e1517238e5c6c2914c#aa8336ee94492b52458ed8e1517238e5c6c2914c"
|
||||
dependencies = [
|
||||
"bincode",
|
||||
"bitflags",
|
||||
@@ -2281,7 +2282,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "rustpython-parser"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/RustPython/RustPython.git?rev=c4b67896662b16b5699a779c0e52aa0ca2587fec#c4b67896662b16b5699a779c0e52aa0ca2587fec"
|
||||
source = "git+https://github.com/RustPython/RustPython.git?rev=aa8336ee94492b52458ed8e1517238e5c6c2914c#aa8336ee94492b52458ed8e1517238e5c6c2914c"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"anyhow",
|
||||
@@ -2947,9 +2948,11 @@ checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c"
|
||||
|
||||
[[package]]
|
||||
name = "unicode_names2"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "029df4cc8238cefc911704ff8fa210853a0f3bce2694d8f51181dd41ee0f3301"
|
||||
version = "0.6.0"
|
||||
source = "git+https://github.com/youknowone/unicode_names2.git?tag=v0.6.0+character-alias#4ce16aa85cbcdd9cc830410f1a72ef9a235f2fde"
|
||||
dependencies = [
|
||||
"phf",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "untrusted"
|
||||
|
||||
@@ -14,8 +14,8 @@ libcst = { git = "https://github.com/charliermarsh/LibCST", rev = "80e4c1399f95e
|
||||
once_cell = { version = "1.16.0" }
|
||||
regex = { version = "1.6.0" }
|
||||
rustc-hash = { version = "1.1.0" }
|
||||
rustpython-common = { git = "https://github.com/RustPython/RustPython.git", rev = "c4b67896662b16b5699a779c0e52aa0ca2587fec" }
|
||||
rustpython-parser = { features = ["lalrpop"], git = "https://github.com/RustPython/RustPython.git", rev = "c4b67896662b16b5699a779c0e52aa0ca2587fec" }
|
||||
rustpython-common = { git = "https://github.com/RustPython/RustPython.git", rev = "aa8336ee94492b52458ed8e1517238e5c6c2914c" }
|
||||
rustpython-parser = { features = ["lalrpop"], git = "https://github.com/RustPython/RustPython.git", rev = "aa8336ee94492b52458ed8e1517238e5c6c2914c" }
|
||||
schemars = { version = "0.8.11" }
|
||||
serde = { version = "1.0.147", features = ["derive"] }
|
||||
serde_json = { version = "1.0.87" }
|
||||
|
||||
120
README.md
120
README.md
@@ -24,17 +24,17 @@ An extremely fast Python linter, written in Rust.
|
||||
<i>Linting the CPython codebase from scratch.</i>
|
||||
</p>
|
||||
|
||||
* ⚡️ 10-100x faster than existing linters
|
||||
* 🐍 Installable via `pip`
|
||||
* 🛠️ `pyproject.toml` support
|
||||
* 🤝 Python 3.11 compatibility
|
||||
* 📦 Built-in caching, to avoid re-analyzing unchanged files
|
||||
* 🔧 Autofix support, for automatic error correction (e.g., automatically remove unused imports)
|
||||
* 📏 Over [500 built-in rules](https://beta.ruff.rs/docs/rules/) (and growing)
|
||||
* ⚖️ [Near-parity](https://beta.ruff.rs/docs/faq/#how-does-ruff-compare-to-flake8) with the built-in Flake8 rule set
|
||||
* 🔌 Native re-implementations of dozens of Flake8 plugins, like flake8-bugbear
|
||||
* ⌨️ First-party editor integrations for [VS Code](https://github.com/charliermarsh/ruff-vscode) and [more](https://github.com/charliermarsh/ruff-lsp)
|
||||
* 🌎 Monorepo-friendly, with [hierarchical and cascading configuration](https://beta.ruff.rs/docs/configuration/#pyprojecttoml-discovery)
|
||||
- ⚡️ 10-100x faster than existing linters
|
||||
- 🐍 Installable via `pip`
|
||||
- 🛠️ `pyproject.toml` support
|
||||
- 🤝 Python 3.11 compatibility
|
||||
- 📦 Built-in caching, to avoid re-analyzing unchanged files
|
||||
- 🔧 Autofix support, for automatic error correction (e.g., automatically remove unused imports)
|
||||
- 📏 Over [500 built-in rules](https://beta.ruff.rs/docs/rules/)
|
||||
- ⚖️ [Near-parity](https://beta.ruff.rs/docs/faq/#how-does-ruff-compare-to-flake8) with the built-in Flake8 rule set
|
||||
- 🔌 Native re-implementations of dozens of Flake8 plugins, like flake8-bugbear
|
||||
- ⌨️ First-party editor integrations for [VS Code](https://github.com/charliermarsh/ruff-vscode) and [more](https://github.com/charliermarsh/ruff-lsp)
|
||||
- 🌎 Monorepo-friendly, with [hierarchical and cascading configuration](https://beta.ruff.rs/docs/configuration/#pyprojecttoml-discovery)
|
||||
|
||||
Ruff aims to be orders of magnitude faster than alternative tools while integrating more
|
||||
functionality behind a single, common interface.
|
||||
@@ -47,11 +47,11 @@ all while executing tens or hundreds of times faster than any individual tool.
|
||||
|
||||
Ruff is extremely actively developed and used in major open-source projects like:
|
||||
|
||||
* [pandas](https://github.com/pandas-dev/pandas)
|
||||
* [FastAPI](https://github.com/tiangolo/fastapi)
|
||||
* [Transformers (Hugging Face)](https://github.com/huggingface/transformers)
|
||||
* [Apache Airflow](https://github.com/apache/airflow)
|
||||
* [SciPy](https://github.com/scipy/scipy)
|
||||
- [pandas](https://github.com/pandas-dev/pandas)
|
||||
- [FastAPI](https://github.com/tiangolo/fastapi)
|
||||
- [Transformers (Hugging Face)](https://github.com/huggingface/transformers)
|
||||
- [Apache Airflow](https://github.com/apache/airflow)
|
||||
- [SciPy](https://github.com/scipy/scipy)
|
||||
|
||||
...and many more.
|
||||
|
||||
@@ -98,13 +98,13 @@ developer of [Zulip](https://github.com/zulip/zulip):
|
||||
For more, see the [documentation](https://beta.ruff.rs/docs/).
|
||||
|
||||
1. [Getting Started](#getting-started)
|
||||
2. [Configuration](#configuration)
|
||||
3. [Rules](#rules)
|
||||
4. [Contributing](#contributing)
|
||||
5. [Support](#support)
|
||||
6. [Acknowledgements](#acknowledgements)
|
||||
7. [Who's Using Ruff?](#whos-using-ruff)
|
||||
8. [License](#license)
|
||||
1. [Configuration](#configuration)
|
||||
1. [Rules](#rules)
|
||||
1. [Contributing](#contributing)
|
||||
1. [Support](#support)
|
||||
1. [Acknowledgements](#acknowledgements)
|
||||
1. [Who's Using Ruff?](#whos-using-ruff)
|
||||
1. [License](#license)
|
||||
|
||||
## Getting Started
|
||||
|
||||
@@ -186,7 +186,6 @@ exclude = [
|
||||
"node_modules",
|
||||
"venv",
|
||||
]
|
||||
per-file-ignores = {}
|
||||
|
||||
# Same as Black.
|
||||
line-length = 88
|
||||
@@ -225,6 +224,9 @@ and a [subset](https://beta.ruff.rs/docs/rules/#error-e) of the `E` category, om
|
||||
stylistic rules made obsolete by the use of an autoformatter, like
|
||||
[Black](https://github.com/psf/black).
|
||||
|
||||
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.
|
||||
|
||||
<!-- End section: Rules -->
|
||||
|
||||
For a complete enumeration of the supported rules, see [_Rules_](https://beta.ruff.rs/docs/rules/).
|
||||
@@ -269,41 +271,41 @@ Ruff is released under the MIT license.
|
||||
|
||||
Ruff is used in a number of major open-source projects, including:
|
||||
|
||||
* [pandas](https://github.com/pandas-dev/pandas)
|
||||
* [FastAPI](https://github.com/tiangolo/fastapi)
|
||||
* [Transformers (Hugging Face)](https://github.com/huggingface/transformers)
|
||||
* [Diffusers (Hugging Face)](https://github.com/huggingface/diffusers)
|
||||
* [Apache Airflow](https://github.com/apache/airflow)
|
||||
* [SciPy](https://github.com/scipy/scipy)
|
||||
* [Zulip](https://github.com/zulip/zulip)
|
||||
* [Bokeh](https://github.com/bokeh/bokeh)
|
||||
* [Pydantic](https://github.com/pydantic/pydantic)
|
||||
* [Dagster](https://github.com/dagster-io/dagster)
|
||||
* [Dagger](https://github.com/dagger/dagger)
|
||||
* [Sphinx](https://github.com/sphinx-doc/sphinx)
|
||||
* [Hatch](https://github.com/pypa/hatch)
|
||||
* [PDM](https://github.com/pdm-project/pdm)
|
||||
* [Jupyter](https://github.com/jupyter-server/jupyter_server)
|
||||
* [Great Expectations](https://github.com/great-expectations/great_expectations)
|
||||
* [ONNX](https://github.com/onnx/onnx)
|
||||
* [Polars](https://github.com/pola-rs/polars)
|
||||
* [Ibis](https://github.com/ibis-project/ibis)
|
||||
* [Synapse (Matrix)](https://github.com/matrix-org/synapse)
|
||||
* [SnowCLI (Snowflake)](https://github.com/Snowflake-Labs/snowcli)
|
||||
* [Dispatch (Netflix)](https://github.com/Netflix/dispatch)
|
||||
* [Saleor](https://github.com/saleor/saleor)
|
||||
* [Pynecone](https://github.com/pynecone-io/pynecone)
|
||||
* [OpenBB](https://github.com/OpenBB-finance/OpenBBTerminal)
|
||||
* [Home Assistant](https://github.com/home-assistant/core)
|
||||
* [Pylint](https://github.com/PyCQA/pylint)
|
||||
* [Cryptography (PyCA)](https://github.com/pyca/cryptography)
|
||||
* [cibuildwheel (PyPA)](https://github.com/pypa/cibuildwheel)
|
||||
* [build (PyPA)](https://github.com/pypa/build)
|
||||
* [Babel](https://github.com/python-babel/babel)
|
||||
* [featuretools](https://github.com/alteryx/featuretools)
|
||||
* [meson-python](https://github.com/mesonbuild/meson-python)
|
||||
* [ZenML](https://github.com/zenml-io/zenml)
|
||||
* [delta-rs](https://github.com/delta-io/delta-rs)
|
||||
- [pandas](https://github.com/pandas-dev/pandas)
|
||||
- [FastAPI](https://github.com/tiangolo/fastapi)
|
||||
- [Transformers (Hugging Face)](https://github.com/huggingface/transformers)
|
||||
- [Diffusers (Hugging Face)](https://github.com/huggingface/diffusers)
|
||||
- [Apache Airflow](https://github.com/apache/airflow)
|
||||
- [SciPy](https://github.com/scipy/scipy)
|
||||
- [Zulip](https://github.com/zulip/zulip)
|
||||
- [Bokeh](https://github.com/bokeh/bokeh)
|
||||
- [Pydantic](https://github.com/pydantic/pydantic)
|
||||
- [Dagster](https://github.com/dagster-io/dagster)
|
||||
- [Dagger](https://github.com/dagger/dagger)
|
||||
- [Sphinx](https://github.com/sphinx-doc/sphinx)
|
||||
- [Hatch](https://github.com/pypa/hatch)
|
||||
- [PDM](https://github.com/pdm-project/pdm)
|
||||
- [Jupyter](https://github.com/jupyter-server/jupyter_server)
|
||||
- [Great Expectations](https://github.com/great-expectations/great_expectations)
|
||||
- [ONNX](https://github.com/onnx/onnx)
|
||||
- [Polars](https://github.com/pola-rs/polars)
|
||||
- [Ibis](https://github.com/ibis-project/ibis)
|
||||
- [Synapse (Matrix)](https://github.com/matrix-org/synapse)
|
||||
- [SnowCLI (Snowflake)](https://github.com/Snowflake-Labs/snowcli)
|
||||
- [Dispatch (Netflix)](https://github.com/Netflix/dispatch)
|
||||
- [Saleor](https://github.com/saleor/saleor)
|
||||
- [Pynecone](https://github.com/pynecone-io/pynecone)
|
||||
- [OpenBB](https://github.com/OpenBB-finance/OpenBBTerminal)
|
||||
- [Home Assistant](https://github.com/home-assistant/core)
|
||||
- [Pylint](https://github.com/PyCQA/pylint)
|
||||
- [Cryptography (PyCA)](https://github.com/pyca/cryptography)
|
||||
- [cibuildwheel (PyPA)](https://github.com/pypa/cibuildwheel)
|
||||
- [build (PyPA)](https://github.com/pypa/build)
|
||||
- [Babel](https://github.com/python-babel/babel)
|
||||
- [featuretools](https://github.com/alteryx/featuretools)
|
||||
- [meson-python](https://github.com/mesonbuild/meson-python)
|
||||
- [ZenML](https://github.com/zenml-io/zenml)
|
||||
- [delta-rs](https://github.com/delta-io/delta-rs)
|
||||
|
||||
## License
|
||||
|
||||
|
||||
@@ -84,7 +84,7 @@ flake8-to-ruff path/to/.flake8 --plugin flake8-builtins --plugin flake8-quotes
|
||||
1. Ruff only supports a subset of the Flake configuration options. `flake8-to-ruff` will warn on and
|
||||
ignore unsupported options in the `.flake8` file (or equivalent). (Similarly, Ruff has a few
|
||||
configuration options that don't exist in Flake8.)
|
||||
2. Ruff will omit any rule codes that are unimplemented or unsupported by Ruff, including rule
|
||||
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.)
|
||||
|
||||
|
||||
@@ -19,6 +19,8 @@ token = "s3cr3t"
|
||||
secrete = "s3cr3t"
|
||||
safe = password = "s3cr3t"
|
||||
password = safe = "s3cr3t"
|
||||
PASSWORD = "s3cr3t"
|
||||
PassWord = "s3cr3t"
|
||||
|
||||
d["password"] = "s3cr3t"
|
||||
d["pass"] = "s3cr3t"
|
||||
@@ -68,6 +70,8 @@ passed_msg = "You have passed!"
|
||||
compassion = "Please don't match!"
|
||||
impassable = "You shall not pass!"
|
||||
passwords = ""
|
||||
PASSWORDS = ""
|
||||
passphrases = ""
|
||||
PassPhrases = ""
|
||||
tokens = ""
|
||||
secrets = ""
|
||||
|
||||
14
crates/ruff/resources/test/fixtures/flake8_pyi/PYI006.py
vendored
Normal file
14
crates/ruff/resources/test/fixtures/flake8_pyi/PYI006.py
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
import sys
|
||||
from sys import version_info as python_version
|
||||
|
||||
if sys.version_info < (3, 9): ... # OK
|
||||
|
||||
if sys.version_info >= (3, 9): ... # OK
|
||||
|
||||
if sys.version_info == (3, 9): ... # OK
|
||||
|
||||
if sys.version_info <= (3, 10): ... # OK
|
||||
|
||||
if sys.version_info > (3, 10): ... # OK
|
||||
|
||||
if python_version > (3, 10): ... # OK
|
||||
18
crates/ruff/resources/test/fixtures/flake8_pyi/PYI006.pyi
vendored
Normal file
18
crates/ruff/resources/test/fixtures/flake8_pyi/PYI006.pyi
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
import sys
|
||||
from sys import version_info as python_version
|
||||
|
||||
if sys.version_info < (3, 9): ... # OK
|
||||
|
||||
if sys.version_info >= (3, 9): ... # OK
|
||||
|
||||
if sys.version_info == (3, 9): ... # OK
|
||||
|
||||
if sys.version_info == (3, 9): ... # Error: PYI006 Use only `<` and `>=` for version info comparisons
|
||||
|
||||
if sys.version_info <= (3, 10): ... # Error: PYI006 Use only `<` and `>=` for version info comparisons
|
||||
|
||||
if sys.version_info <= (3, 10): ... # Error: PYI006 Use only `<` and `>=` for version info comparisons
|
||||
|
||||
if sys.version_info > (3, 10): ... # Error: PYI006 Use only `<` and `>=` for version info comparisons
|
||||
|
||||
if python_version > (3, 10): ... # Error: PYI006 Use only `<` and `>=` for version info comparisons
|
||||
@@ -74,3 +74,13 @@ elif b == b"two":
|
||||
return 2
|
||||
elif a == b"three":
|
||||
return 3
|
||||
|
||||
# SIM116
|
||||
if func_name == "create":
|
||||
return "A"
|
||||
elif func_name == "modify":
|
||||
return "M"
|
||||
elif func_name == "remove":
|
||||
return "D"
|
||||
elif func_name == "move":
|
||||
return "MV"
|
||||
|
||||
@@ -11,6 +11,7 @@ YODA > age # SIM300
|
||||
YODA >= age # SIM300
|
||||
JediOrder.YODA == age # SIM300
|
||||
0 < (number - 100) # SIM300
|
||||
SomeClass().settings.SOME_CONSTANT_VALUE > (60 * 60) # SIM300
|
||||
|
||||
# OK
|
||||
compare == "yoda"
|
||||
|
||||
50
crates/ruff/resources/test/fixtures/pycodestyle/E25.py
vendored
Normal file
50
crates/ruff/resources/test/fixtures/pycodestyle/E25.py
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
#: E251 E251
|
||||
def foo(bar = False):
|
||||
'''Test function with an error in declaration'''
|
||||
pass
|
||||
#: E251
|
||||
foo(bar= True)
|
||||
#: E251
|
||||
foo(bar =True)
|
||||
#: E251 E251
|
||||
foo(bar = True)
|
||||
#: E251
|
||||
y = bar(root= "sdasd")
|
||||
#: E251:2:29
|
||||
parser.add_argument('--long-option',
|
||||
default=
|
||||
"/rather/long/filesystem/path/here/blah/blah/blah")
|
||||
#: E251:1:45
|
||||
parser.add_argument('--long-option', default
|
||||
="/rather/long/filesystem/path/here/blah/blah/blah")
|
||||
#: E251:3:8 E251:3:10
|
||||
foo(True,
|
||||
baz=(1, 2),
|
||||
biz = 'foo'
|
||||
)
|
||||
#: Okay
|
||||
foo(bar=(1 == 1))
|
||||
foo(bar=(1 != 1))
|
||||
foo(bar=(1 >= 1))
|
||||
foo(bar=(1 <= 1))
|
||||
(options, args) = parser.parse_args()
|
||||
d[type(None)] = _deepcopy_atomic
|
||||
|
||||
# Annotated Function Definitions
|
||||
#: Okay
|
||||
def munge(input: AnyStr, sep: AnyStr = None, limit=1000,
|
||||
extra: Union[str, dict] = None) -> AnyStr:
|
||||
pass
|
||||
#: Okay
|
||||
async def add(a: int = 0, b: int = 0) -> int:
|
||||
return a + b
|
||||
# Previously E251 four times
|
||||
#: E271:1:6
|
||||
async def add(a: int = 0, b: int = 0) -> int:
|
||||
return a + b
|
||||
#: E252:1:15 E252:1:16 E252:1:27 E252:1:36
|
||||
def add(a: int=0, b: int =0, c: int= 0) -> int:
|
||||
return a + b + c
|
||||
#: Okay
|
||||
def add(a: int = _default(name='f')):
|
||||
return a
|
||||
145
crates/ruff/resources/test/fixtures/pycodestyle/W19.py
vendored
Normal file
145
crates/ruff/resources/test/fixtures/pycodestyle/W19.py
vendored
Normal file
@@ -0,0 +1,145 @@
|
||||
#: W191
|
||||
if False:
|
||||
print # indented with 1 tab
|
||||
#:
|
||||
|
||||
|
||||
#: W191
|
||||
y = x == 2 \
|
||||
or x == 3
|
||||
#: E101 W191 W504
|
||||
if (
|
||||
x == (
|
||||
3
|
||||
) or
|
||||
y == 4):
|
||||
pass
|
||||
#: E101 W191
|
||||
if x == 2 \
|
||||
or y > 1 \
|
||||
or x == 3:
|
||||
pass
|
||||
#: E101 W191
|
||||
if x == 2 \
|
||||
or y > 1 \
|
||||
or x == 3:
|
||||
pass
|
||||
#:
|
||||
|
||||
#: E101 W191 W504
|
||||
if (foo == bar and
|
||||
baz == bop):
|
||||
pass
|
||||
#: E101 W191 W504
|
||||
if (
|
||||
foo == bar and
|
||||
baz == bop
|
||||
):
|
||||
pass
|
||||
#:
|
||||
|
||||
#: E101 E101 W191 W191
|
||||
if start[1] > end_col and not (
|
||||
over_indent == 4 and indent_next):
|
||||
return (0, "E121 continuation line over-"
|
||||
"indented for visual indent")
|
||||
#:
|
||||
|
||||
#: E101 W191
|
||||
|
||||
|
||||
def long_function_name(
|
||||
var_one, var_two, var_three,
|
||||
var_four):
|
||||
print(var_one)
|
||||
#: E101 W191 W504
|
||||
if ((row < 0 or self.moduleCount <= row or
|
||||
col < 0 or self.moduleCount <= col)):
|
||||
raise Exception("%s,%s - %s" % (row, col, self.moduleCount))
|
||||
#: E101 E101 E101 E101 W191 W191 W191 W191 W191 W191
|
||||
if bar:
|
||||
return (
|
||||
start, 'E121 lines starting with a '
|
||||
'closing bracket should be indented '
|
||||
"to match that of the opening "
|
||||
"bracket's line"
|
||||
)
|
||||
#
|
||||
#: E101 W191 W504
|
||||
# you want vertical alignment, so use a parens
|
||||
if ((foo.bar("baz") and
|
||||
foo.bar("bop")
|
||||
)):
|
||||
print "yes"
|
||||
#: E101 W191 W504
|
||||
# also ok, but starting to look like LISP
|
||||
if ((foo.bar("baz") and
|
||||
foo.bar("bop"))):
|
||||
print "yes"
|
||||
#: E101 W191 W504
|
||||
if (a == 2 or
|
||||
b == "abc def ghi"
|
||||
"jkl mno"):
|
||||
return True
|
||||
#: E101 W191 W504
|
||||
if (a == 2 or
|
||||
b == """abc def ghi
|
||||
jkl mno"""):
|
||||
return True
|
||||
#: W191:2:1 W191:3:1 E101:3:2
|
||||
if length > options.max_line_length:
|
||||
return options.max_line_length, \
|
||||
"E501 line too long (%d characters)" % length
|
||||
|
||||
|
||||
#
|
||||
#: E101 W191 W191 W504
|
||||
if os.path.exists(os.path.join(path, PEP8_BIN)):
|
||||
cmd = ([os.path.join(path, PEP8_BIN)] +
|
||||
self._pep8_options(targetfile))
|
||||
#: W191
|
||||
'''
|
||||
multiline string with tab in it'''
|
||||
#: E101 W191
|
||||
'''multiline string
|
||||
with tabs
|
||||
and spaces
|
||||
'''
|
||||
#: Okay
|
||||
'''sometimes, you just need to go nuts in a multiline string
|
||||
and allow all sorts of crap
|
||||
like mixed tabs and spaces
|
||||
|
||||
or trailing whitespace
|
||||
or long long long long long long long long long long long long long long long long long lines
|
||||
''' # nopep8
|
||||
#: Okay
|
||||
'''this one
|
||||
will get no warning
|
||||
even though the noqa comment is not immediately after the string
|
||||
''' + foo # noqa
|
||||
#
|
||||
#: E101 W191
|
||||
if foo is None and bar is "bop" and \
|
||||
blah == 'yeah':
|
||||
blah = 'yeahnah'
|
||||
|
||||
|
||||
#
|
||||
#: W191 W191 W191
|
||||
if True:
|
||||
foo(
|
||||
1,
|
||||
2)
|
||||
#: W191 W191 W191 W191 W191
|
||||
def test_keys(self):
|
||||
"""areas.json - All regions are accounted for."""
|
||||
expected = set([
|
||||
u'Norrbotten',
|
||||
u'V\xe4sterbotten',
|
||||
])
|
||||
#: W191
|
||||
x = [
|
||||
'abc'
|
||||
]
|
||||
#:
|
||||
10
crates/ruff/resources/test/fixtures/pyflakes/F401_10.py
vendored
Normal file
10
crates/ruff/resources/test/fixtures/pyflakes/F401_10.py
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
"""Test: imports within `ModuleNotFoundError` handlers."""
|
||||
|
||||
|
||||
def check_orjson():
|
||||
try:
|
||||
import orjson
|
||||
|
||||
return True
|
||||
except ModuleNotFoundError:
|
||||
return False
|
||||
@@ -16,6 +16,9 @@ logging.error("Example log %s, %s", "foo", "bar", "baz", *args)
|
||||
# do not handle calls with **kwargs
|
||||
logging.error("Example log %s, %s", "foo", "bar", "baz", **kwargs)
|
||||
|
||||
# do not handle keyword arguments
|
||||
logging.error("%(objects)d modifications: %(modifications)d errors: %(errors)d")
|
||||
|
||||
import warning
|
||||
|
||||
warning.warning("Hello %s %s", "World!")
|
||||
|
||||
@@ -12,6 +12,9 @@ logging.error("Example log %s, %s", "foo", "bar", "baz", *args)
|
||||
# do not handle calls with **kwargs
|
||||
logging.error("Example log %s, %s", "foo", "bar", "baz", **kwargs)
|
||||
|
||||
# do not handle keyword arguments
|
||||
logging.error("%(objects)d modifications: %(modifications)d errors: %(errors)d", {"objects": 1, "modifications": 1, "errors": 1})
|
||||
|
||||
import warning
|
||||
|
||||
warning.warning("Hello %s", "World!", "again")
|
||||
|
||||
@@ -28,3 +28,10 @@ def f(x: IList[str]) -> None:
|
||||
|
||||
def f(x: "List[str]") -> None:
|
||||
...
|
||||
|
||||
|
||||
list = "abc"
|
||||
|
||||
|
||||
def f(x: List[str]) -> None:
|
||||
...
|
||||
|
||||
@@ -35,3 +35,9 @@ MyType = TypedDict("MyType", {"in": int, "x-y": int})
|
||||
# unpacking (OK)
|
||||
c = {"c": float}
|
||||
MyType = TypedDict("MyType", {"a": int, "b": str, **c})
|
||||
|
||||
# Empty dict literal
|
||||
MyType = TypedDict("MyType", {})
|
||||
|
||||
# Empty dict call
|
||||
MyType = TypedDict("MyType", dict())
|
||||
|
||||
@@ -23,3 +23,9 @@ MyType = NamedTuple(
|
||||
|
||||
# invalid identifiers (OK)
|
||||
MyType = NamedTuple("MyType", [("x-y", int), ("b", tuple[str, ...])])
|
||||
|
||||
# no fields
|
||||
MyType = typing.NamedTuple("MyType")
|
||||
|
||||
# empty fields
|
||||
MyType = typing.NamedTuple("MyType", [])
|
||||
|
||||
7
crates/ruff/resources/test/fixtures/pyupgrade/UP038.py
vendored
Normal file
7
crates/ruff/resources/test/fixtures/pyupgrade/UP038.py
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
isinstance(1, (int, float)) # UP038
|
||||
issubclass("yes", (int, float, str)) # UP038
|
||||
|
||||
isinstance(1, int) # OK
|
||||
issubclass("yes", int) # OK
|
||||
isinstance(1, int | float) # OK
|
||||
issubclass("yes", int | str) # OK
|
||||
@@ -1,15 +0,0 @@
|
||||
def f(*args, **kwargs):
|
||||
pass
|
||||
|
||||
|
||||
a = (1, 2)
|
||||
b = (3, 4)
|
||||
c = (5, 6)
|
||||
d = (7, 8)
|
||||
|
||||
f(a, b)
|
||||
f(a, kw=b)
|
||||
f(*a, kw=b)
|
||||
f(kw=a, *b)
|
||||
f(kw=a, *b, *c)
|
||||
f(*a, kw=b, *c, kw1=d)
|
||||
@@ -30,3 +30,11 @@ def good():
|
||||
raise e # This is verbose violation, shouldn't trigger no cause
|
||||
except Exception:
|
||||
raise # Just re-raising don't need 'from'
|
||||
|
||||
|
||||
def good():
|
||||
try:
|
||||
from mod import f
|
||||
except ImportError:
|
||||
def f():
|
||||
raise MyException() # Raising within a new scope is fine
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use std::path::Path;
|
||||
|
||||
use bitflags::bitflags;
|
||||
use itertools::Itertools;
|
||||
use log::error;
|
||||
use once_cell::sync::Lazy;
|
||||
@@ -575,33 +576,32 @@ pub fn has_non_none_keyword(keywords: &[Keyword], keyword: &str) -> bool {
|
||||
})
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
pub struct Exceptions: u32 {
|
||||
const NAME_ERROR = 0b0000_0001;
|
||||
const MODULE_NOT_FOUND_ERROR = 0b0000_0010;
|
||||
}
|
||||
}
|
||||
|
||||
/// Extract the names of all handled exceptions.
|
||||
pub fn extract_handler_names(handlers: &[Excepthandler]) -> Vec<CallPath> {
|
||||
// TODO(charlie): Use `resolve_call_path` to avoid false positives for
|
||||
// overridden builtins.
|
||||
let mut handler_names = vec![];
|
||||
pub fn extract_handled_exceptions(handlers: &[Excepthandler]) -> Vec<&Expr> {
|
||||
let mut handled_exceptions = Vec::new();
|
||||
for handler in handlers {
|
||||
match &handler.node {
|
||||
ExcepthandlerKind::ExceptHandler { type_, .. } => {
|
||||
if let Some(type_) = type_ {
|
||||
if let ExprKind::Tuple { elts, .. } = &type_.node {
|
||||
for type_ in elts {
|
||||
let call_path = collect_call_path(type_);
|
||||
if !call_path.is_empty() {
|
||||
handler_names.push(call_path);
|
||||
}
|
||||
handled_exceptions.push(type_);
|
||||
}
|
||||
} else {
|
||||
let call_path = collect_call_path(type_);
|
||||
if !call_path.is_empty() {
|
||||
handler_names.push(call_path);
|
||||
}
|
||||
handled_exceptions.push(type_);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
handler_names
|
||||
handled_exceptions
|
||||
}
|
||||
|
||||
/// Return the set of all bound argument names.
|
||||
@@ -765,7 +765,7 @@ pub fn from_relative_import<'a>(module: &'a [String], name: &'a str) -> CallPath
|
||||
call_path
|
||||
}
|
||||
|
||||
/// A [`Visitor`] that collects all return statements in a function or method.
|
||||
/// A [`Visitor`] that collects all `return` statements in a function or method.
|
||||
#[derive(Default)]
|
||||
pub struct ReturnStatementVisitor<'a> {
|
||||
pub returns: Vec<Option<&'a Expr>>,
|
||||
@@ -786,6 +786,48 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// A [`Visitor`] that collects all `raise` statements in a function or method.
|
||||
#[derive(Default)]
|
||||
pub struct RaiseStatementVisitor<'a> {
|
||||
pub raises: Vec<(Range, Option<&'a Expr>, Option<&'a Expr>)>,
|
||||
}
|
||||
|
||||
impl<'a, 'b> Visitor<'b> for RaiseStatementVisitor<'b>
|
||||
where
|
||||
'b: 'a,
|
||||
{
|
||||
fn visit_stmt(&mut self, stmt: &'b Stmt) {
|
||||
match &stmt.node {
|
||||
StmtKind::Raise { exc, cause } => {
|
||||
self.raises
|
||||
.push((Range::from_located(stmt), exc.as_deref(), cause.as_deref()));
|
||||
}
|
||||
StmtKind::ClassDef { .. }
|
||||
| StmtKind::FunctionDef { .. }
|
||||
| StmtKind::AsyncFunctionDef { .. }
|
||||
| StmtKind::Try { .. }
|
||||
| StmtKind::TryStar { .. } => {}
|
||||
StmtKind::If { body, orelse, .. } => {
|
||||
visitor::walk_body(self, body);
|
||||
visitor::walk_body(self, orelse);
|
||||
}
|
||||
StmtKind::While { body, .. }
|
||||
| StmtKind::With { body, .. }
|
||||
| StmtKind::AsyncWith { body, .. }
|
||||
| StmtKind::For { body, .. }
|
||||
| StmtKind::AsyncFor { body, .. } => {
|
||||
visitor::walk_body(self, body);
|
||||
}
|
||||
StmtKind::Match { cases, .. } => {
|
||||
for case in cases {
|
||||
visitor::walk_body(self, &case.body);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert a location within a file (relative to `base`) to an absolute
|
||||
/// position.
|
||||
pub fn to_absolute(relative: Location, base: Location) -> Location {
|
||||
|
||||
@@ -19,7 +19,8 @@ use rustpython_parser::ast::{
|
||||
use smallvec::smallvec;
|
||||
|
||||
use crate::ast::helpers::{
|
||||
binding_range, collect_call_path, extract_handler_names, from_relative_import, to_module_path,
|
||||
binding_range, collect_call_path, extract_handled_exceptions, from_relative_import,
|
||||
to_module_path, Exceptions,
|
||||
};
|
||||
use crate::ast::operations::{extract_all_names, AllNamesFlags};
|
||||
use crate::ast::relocate::relocate_expr;
|
||||
@@ -109,7 +110,7 @@ pub struct Checker<'a> {
|
||||
pub(crate) seen_import_boundary: bool,
|
||||
futures_allowed: bool,
|
||||
annotations_future_enabled: bool,
|
||||
except_handlers: Vec<Vec<Vec<&'a str>>>,
|
||||
handled_exceptions: Vec<Exceptions>,
|
||||
// Check-specific state.
|
||||
pub(crate) flake8_bugbear_seen: Vec<&'a Expr>,
|
||||
}
|
||||
@@ -178,7 +179,7 @@ impl<'a> Checker<'a> {
|
||||
seen_import_boundary: false,
|
||||
futures_allowed: true,
|
||||
annotations_future_enabled: is_interface_definition,
|
||||
except_handlers: vec![],
|
||||
handled_exceptions: vec![],
|
||||
// Check-specific state.
|
||||
flake8_bugbear_seen: vec![],
|
||||
}
|
||||
@@ -233,6 +234,14 @@ impl<'a> Checker<'a> {
|
||||
.map_or(false, |binding| binding.kind.is_builtin())
|
||||
}
|
||||
|
||||
/// Resolves the call path, e.g. if you have a file
|
||||
///
|
||||
/// ```python
|
||||
/// from sys import version_info as python_version
|
||||
/// print(python_version)
|
||||
/// ```
|
||||
///
|
||||
/// then `python_version` from the print statement will resolve to `sys.version_info`.
|
||||
pub fn resolve_call_path<'b>(&'a self, value: &'b Expr) -> Option<CallPath<'a>>
|
||||
where
|
||||
'b: 'a,
|
||||
@@ -962,6 +971,13 @@ where
|
||||
pyupgrade::rules::rewrite_mock_import(self, stmt);
|
||||
}
|
||||
|
||||
// If a module is imported within a `ModuleNotFoundError` body, treat that as a
|
||||
// synthetic usage.
|
||||
let is_handled = self
|
||||
.handled_exceptions
|
||||
.iter()
|
||||
.any(|exceptions| exceptions.contains(Exceptions::MODULE_NOT_FOUND_ERROR));
|
||||
|
||||
for alias in names {
|
||||
if alias.node.name == "__future__" {
|
||||
let name = alias.node.asname.as_ref().unwrap_or(&alias.node.name);
|
||||
@@ -1004,7 +1020,18 @@ where
|
||||
Binding {
|
||||
kind: BindingKind::SubmoduleImportation(name, full_name),
|
||||
runtime_usage: None,
|
||||
synthetic_usage: None,
|
||||
synthetic_usage: if is_handled {
|
||||
Some((
|
||||
self.scopes[*(self
|
||||
.scope_stack
|
||||
.last()
|
||||
.expect("No current scope found"))]
|
||||
.id,
|
||||
Range::from_located(alias),
|
||||
))
|
||||
} else {
|
||||
None
|
||||
},
|
||||
typing_usage: None,
|
||||
range: Range::from_located(alias),
|
||||
source: Some(self.current_stmt().clone()),
|
||||
@@ -1012,6 +1039,14 @@ where
|
||||
},
|
||||
);
|
||||
} else {
|
||||
// Treat explicit re-export as usage (e.g., `from .applications
|
||||
// import FastAPI as FastAPI`).
|
||||
let is_explicit_reexport = alias
|
||||
.node
|
||||
.asname
|
||||
.as_ref()
|
||||
.map_or(false, |asname| asname == &alias.node.name);
|
||||
|
||||
// Given `import foo`, `name` and `full_name` would both be `foo`.
|
||||
// Given `import foo as bar`, `name` would be `bar` and `full_name` would
|
||||
// be `foo`.
|
||||
@@ -1022,14 +1057,7 @@ where
|
||||
Binding {
|
||||
kind: BindingKind::Importation(name, full_name),
|
||||
runtime_usage: None,
|
||||
// Treat explicit re-export as usage (e.g., `import applications
|
||||
// as applications`).
|
||||
synthetic_usage: if alias
|
||||
.node
|
||||
.asname
|
||||
.as_ref()
|
||||
.map_or(false, |asname| asname == &alias.node.name)
|
||||
{
|
||||
synthetic_usage: if is_handled || is_explicit_reexport {
|
||||
Some((
|
||||
self.scopes[*(self
|
||||
.scope_stack
|
||||
@@ -1285,6 +1313,13 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
// If a module is imported within a `ModuleNotFoundError` body, treat that as a
|
||||
// synthetic usage.
|
||||
let is_handled = self
|
||||
.handled_exceptions
|
||||
.iter()
|
||||
.any(|exceptions| exceptions.contains(Exceptions::MODULE_NOT_FOUND_ERROR));
|
||||
|
||||
for alias in names {
|
||||
if let Some("__future__") = module.as_deref() {
|
||||
let name = alias.node.asname.as_ref().unwrap_or(&alias.node.name);
|
||||
@@ -1331,7 +1366,18 @@ where
|
||||
Binding {
|
||||
kind: BindingKind::StarImportation(*level, module.clone()),
|
||||
runtime_usage: None,
|
||||
synthetic_usage: None,
|
||||
synthetic_usage: if is_handled {
|
||||
Some((
|
||||
self.scopes[*(self
|
||||
.scope_stack
|
||||
.last()
|
||||
.expect("No current scope found"))]
|
||||
.id,
|
||||
Range::from_located(alias),
|
||||
))
|
||||
} else {
|
||||
None
|
||||
},
|
||||
typing_usage: None,
|
||||
range: Range::from_located(stmt),
|
||||
source: Some(self.current_stmt().clone()),
|
||||
@@ -1375,6 +1421,14 @@ where
|
||||
self.check_builtin_shadowing(asname, stmt, false);
|
||||
}
|
||||
|
||||
// Treat explicit re-export as usage (e.g., `from .applications
|
||||
// import FastAPI as FastAPI`).
|
||||
let is_explicit_reexport = alias
|
||||
.node
|
||||
.asname
|
||||
.as_ref()
|
||||
.map_or(false, |asname| asname == &alias.node.name);
|
||||
|
||||
// Given `from foo import bar`, `name` would be "bar" and `full_name` would
|
||||
// be "foo.bar". Given `from foo import bar as baz`, `name` would be "baz"
|
||||
// and `full_name` would be "foo.bar".
|
||||
@@ -1384,33 +1438,25 @@ where
|
||||
module.as_deref(),
|
||||
&alias.node.name,
|
||||
);
|
||||
let range = Range::from_located(alias);
|
||||
self.add_binding(
|
||||
name,
|
||||
Binding {
|
||||
kind: BindingKind::FromImportation(name, full_name),
|
||||
runtime_usage: None,
|
||||
// Treat explicit re-export as usage (e.g., `from .applications
|
||||
// import FastAPI as FastAPI`).
|
||||
synthetic_usage: if alias
|
||||
.node
|
||||
.asname
|
||||
.as_ref()
|
||||
.map_or(false, |asname| asname == &alias.node.name)
|
||||
{
|
||||
synthetic_usage: if is_handled || is_explicit_reexport {
|
||||
Some((
|
||||
self.scopes[*(self
|
||||
.scope_stack
|
||||
.last()
|
||||
.expect("No current scope found"))]
|
||||
.id,
|
||||
range,
|
||||
Range::from_located(alias),
|
||||
))
|
||||
} else {
|
||||
None
|
||||
},
|
||||
typing_usage: None,
|
||||
range,
|
||||
range: Range::from_located(alias),
|
||||
source: Some(self.current_stmt().clone()),
|
||||
context: self.execution_context(),
|
||||
},
|
||||
@@ -1636,7 +1682,14 @@ where
|
||||
flake8_simplify::rules::needless_bool(self, stmt);
|
||||
}
|
||||
if self.settings.rules.enabled(&Rule::ManualDictLookup) {
|
||||
flake8_simplify::rules::manual_dict_lookup(self, stmt, test, body, orelse);
|
||||
flake8_simplify::rules::manual_dict_lookup(
|
||||
self,
|
||||
stmt,
|
||||
test,
|
||||
body,
|
||||
orelse,
|
||||
self.current_stmt_parent().map(std::convert::Into::into),
|
||||
);
|
||||
}
|
||||
if self.settings.rules.enabled(&Rule::UseTernaryOperator) {
|
||||
flake8_simplify::rules::use_ternary_operator(
|
||||
@@ -2113,17 +2166,23 @@ where
|
||||
orelse,
|
||||
finalbody,
|
||||
} => {
|
||||
// TODO(charlie): The use of `smallvec` here leads to a lifetime issue.
|
||||
let handler_names = extract_handler_names(handlers)
|
||||
.into_iter()
|
||||
.map(|call_path| call_path.to_vec())
|
||||
.collect();
|
||||
self.except_handlers.push(handler_names);
|
||||
let mut handled_exceptions = Exceptions::empty();
|
||||
for type_ in extract_handled_exceptions(handlers) {
|
||||
if let Some(call_path) = self.resolve_call_path(type_) {
|
||||
if call_path.as_slice() == ["", "NameError"] {
|
||||
handled_exceptions |= Exceptions::NAME_ERROR;
|
||||
} else if call_path.as_slice() == ["", "ModuleNotFoundError"] {
|
||||
handled_exceptions |= Exceptions::MODULE_NOT_FOUND_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.handled_exceptions.push(handled_exceptions);
|
||||
if self.settings.rules.enabled(&Rule::JumpStatementInFinally) {
|
||||
flake8_bugbear::rules::jump_statement_in_finally(self, finalbody);
|
||||
}
|
||||
self.visit_body(body);
|
||||
self.except_handlers.pop();
|
||||
self.handled_exceptions.pop();
|
||||
|
||||
self.in_exception_handler = true;
|
||||
for excepthandler in handlers {
|
||||
@@ -2525,6 +2584,9 @@ where
|
||||
if self.settings.rules.enabled(&Rule::OSErrorAlias) {
|
||||
pyupgrade::rules::os_error_alias(self, &expr);
|
||||
}
|
||||
if self.settings.rules.enabled(&Rule::IsinstanceWithTuple) {
|
||||
pyupgrade::rules::use_pep604_isinstance(self, expr, func, args);
|
||||
}
|
||||
|
||||
// flake8-print
|
||||
if self.settings.rules.enabled(&Rule::PrintFound)
|
||||
@@ -2939,18 +3001,6 @@ where
|
||||
flake8_pytest_style::rules::fail_call(self, func, args, keywords);
|
||||
}
|
||||
|
||||
// ruff
|
||||
if self
|
||||
.settings
|
||||
.rules
|
||||
.enabled(&Rule::KeywordArgumentBeforeStarArgument)
|
||||
{
|
||||
self.diagnostics
|
||||
.extend(ruff::rules::keyword_argument_before_star_argument(
|
||||
args, keywords,
|
||||
));
|
||||
}
|
||||
|
||||
// flake8-simplify
|
||||
if self
|
||||
.settings
|
||||
@@ -3384,6 +3434,16 @@ where
|
||||
comparators,
|
||||
);
|
||||
}
|
||||
|
||||
if self.settings.rules.enabled(&Rule::BadVersionInfoComparison) {
|
||||
flake8_pyi::rules::bad_version_info_comparison(
|
||||
self,
|
||||
expr,
|
||||
left,
|
||||
ops,
|
||||
comparators,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
ExprKind::Constant {
|
||||
@@ -4480,13 +4540,12 @@ impl<'a> Checker<'a> {
|
||||
}
|
||||
|
||||
// Avoid flagging if NameError is handled.
|
||||
if let Some(handler_names) = self.except_handlers.last() {
|
||||
if handler_names
|
||||
.iter()
|
||||
.any(|call_path| call_path.as_slice() == ["NameError"])
|
||||
{
|
||||
return;
|
||||
}
|
||||
if self
|
||||
.handled_exceptions
|
||||
.iter()
|
||||
.any(|handler_names| handler_names.contains(Exceptions::NAME_ERROR))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
self.diagnostics.push(Diagnostic::new(
|
||||
|
||||
@@ -8,7 +8,8 @@ use crate::registry::Diagnostic;
|
||||
use crate::rules::pycodestyle::logical_lines::{iter_logical_lines, TokenFlags};
|
||||
use crate::rules::pycodestyle::rules::{
|
||||
extraneous_whitespace, indentation, missing_whitespace_after_keyword, space_around_operator,
|
||||
whitespace_around_keywords, whitespace_before_comment,
|
||||
whitespace_around_keywords, whitespace_around_named_parameter_equals,
|
||||
whitespace_before_comment,
|
||||
};
|
||||
use crate::settings::Settings;
|
||||
use crate::source_code::{Locator, Stylist};
|
||||
@@ -132,6 +133,21 @@ pub fn check_logical_lines(
|
||||
}
|
||||
}
|
||||
}
|
||||
if line.flags.contains(TokenFlags::OPERATOR) {
|
||||
for (location, kind) in
|
||||
whitespace_around_named_parameter_equals(&line.tokens, &line.text)
|
||||
{
|
||||
if settings.rules.enabled(kind.rule()) {
|
||||
diagnostics.push(Diagnostic {
|
||||
kind,
|
||||
location,
|
||||
end_location: location,
|
||||
fix: None,
|
||||
parent: None,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (index, kind) in indentation(
|
||||
&line,
|
||||
|
||||
@@ -8,8 +8,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, line_too_long, mixed_spaces_and_tabs, no_newline_at_end_of_file,
|
||||
trailing_whitespace,
|
||||
doc_line_too_long, indentation_contains_tabs, line_too_long, mixed_spaces_and_tabs,
|
||||
no_newline_at_end_of_file, trailing_whitespace,
|
||||
};
|
||||
use crate::rules::pygrep_hooks::rules::{blanket_noqa, blanket_type_ignore};
|
||||
use crate::rules::pylint;
|
||||
@@ -45,6 +45,7 @@ pub fn check_physical_lines(
|
||||
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);
|
||||
|
||||
let fix_unnecessary_coding_comment =
|
||||
autofix.into() && settings.rules.should_fix(&Rule::UTF8EncodingDeclaration);
|
||||
@@ -149,6 +150,12 @@ pub fn check_physical_lines(
|
||||
diagnostics.push(diagnostic);
|
||||
}
|
||||
}
|
||||
|
||||
if enforce_indentation_contains_tabs {
|
||||
if let Some(diagnostic) = indentation_contains_tabs(index, line) {
|
||||
diagnostics.push(diagnostic);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if enforce_no_newline_at_end_of_file {
|
||||
|
||||
@@ -37,6 +37,10 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<Rule> {
|
||||
#[cfg(feature = "logical_lines")]
|
||||
(Pycodestyle, "E224") => Rule::TabAfterOperator,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
(Pycodestyle, "E251") => Rule::UnexpectedSpacesAroundKeywordParameterEquals,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
(Pycodestyle, "E252") => Rule::MissingWhitespaceAroundParameterEquals,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
(Pycodestyle, "E261") => Rule::TooFewSpacesBeforeInlineComment,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
(Pycodestyle, "E262") => Rule::NoSpaceAfterInlineComment,
|
||||
@@ -74,6 +78,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<Rule> {
|
||||
(Pycodestyle, "E999") => Rule::SyntaxError,
|
||||
|
||||
// pycodestyle warnings
|
||||
(Pycodestyle, "W191") => Rule::IndentationContainsTabs,
|
||||
(Pycodestyle, "W291") => Rule::TrailingWhitespace,
|
||||
(Pycodestyle, "W292") => Rule::NoNewLineAtEndOfFile,
|
||||
(Pycodestyle, "W293") => Rule::BlankLineContainsWhitespace,
|
||||
@@ -339,6 +344,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<Rule> {
|
||||
(Pyupgrade, "035") => Rule::ImportReplacements,
|
||||
(Pyupgrade, "036") => Rule::OutdatedVersionBlock,
|
||||
(Pyupgrade, "037") => Rule::QuotedAnnotation,
|
||||
(Pyupgrade, "038") => Rule::IsinstanceWithTuple,
|
||||
|
||||
// pydocstyle
|
||||
(Pydocstyle, "100") => Rule::PublicModule,
|
||||
@@ -487,6 +493,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<Rule> {
|
||||
|
||||
// flake8-pyi
|
||||
(Flake8Pyi, "001") => Rule::PrefixTypeParams,
|
||||
(Flake8Pyi, "006") => Rule::BadVersionInfoComparison,
|
||||
(Flake8Pyi, "007") => Rule::UnrecognizedPlatformCheck,
|
||||
(Flake8Pyi, "008") => Rule::UnrecognizedPlatformName,
|
||||
(Flake8Pyi, "009") => Rule::PassStatementStubBody,
|
||||
@@ -616,7 +623,6 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<Rule> {
|
||||
(Ruff, "001") => Rule::AmbiguousUnicodeCharacterString,
|
||||
(Ruff, "002") => Rule::AmbiguousUnicodeCharacterDocstring,
|
||||
(Ruff, "003") => Rule::AmbiguousUnicodeCharacterComment,
|
||||
(Ruff, "004") => Rule::KeywordArgumentBeforeStarArgument,
|
||||
(Ruff, "005") => Rule::UnpackInsteadOfConcatenatingToCollectionLiteral,
|
||||
(Ruff, "006") => Rule::AsyncioDanglingTask,
|
||||
(Ruff, "100") => Rule::UnusedNOQA,
|
||||
|
||||
@@ -201,8 +201,8 @@ pub fn check(contents: &str, options: JsValue) -> Result<JsValue, JsValue> {
|
||||
&indexer,
|
||||
&directives,
|
||||
&settings,
|
||||
flags::Autofix::Enabled,
|
||||
flags::Noqa::Enabled,
|
||||
flags::Autofix::Enabled,
|
||||
);
|
||||
|
||||
let messages: Vec<ExpandedMessage> = diagnostics
|
||||
|
||||
@@ -62,8 +62,8 @@ pub fn check_path(
|
||||
indexer: &Indexer,
|
||||
directives: &Directives,
|
||||
settings: &Settings,
|
||||
autofix: flags::Autofix,
|
||||
noqa: flags::Noqa,
|
||||
autofix: flags::Autofix,
|
||||
) -> LinterResult<Vec<Diagnostic>> {
|
||||
// Aggregate all diagnostics.
|
||||
let mut diagnostics = vec![];
|
||||
@@ -255,8 +255,8 @@ pub fn add_noqa_to_path(path: &Path, package: Option<&Path>, settings: &Settings
|
||||
&indexer,
|
||||
&directives,
|
||||
settings,
|
||||
flags::Autofix::Disabled,
|
||||
flags::Noqa::Disabled,
|
||||
flags::Autofix::Disabled,
|
||||
);
|
||||
|
||||
// Log any parse errors.
|
||||
@@ -287,6 +287,7 @@ pub fn lint_only(
|
||||
path: &Path,
|
||||
package: Option<&Path>,
|
||||
settings: &Settings,
|
||||
noqa: flags::Noqa,
|
||||
autofix: flags::Autofix,
|
||||
) -> LinterResult<Vec<Message>> {
|
||||
// Tokenize once.
|
||||
@@ -316,8 +317,8 @@ pub fn lint_only(
|
||||
&indexer,
|
||||
&directives,
|
||||
settings,
|
||||
noqa,
|
||||
autofix,
|
||||
flags::Noqa::Enabled,
|
||||
);
|
||||
|
||||
// Convert from diagnostics to messages.
|
||||
@@ -345,6 +346,7 @@ pub fn lint_fix<'a>(
|
||||
contents: &'a str,
|
||||
path: &Path,
|
||||
package: Option<&Path>,
|
||||
noqa: flags::Noqa,
|
||||
settings: &Settings,
|
||||
) -> Result<(LinterResult<Vec<Message>>, Cow<'a, str>, FixTable)> {
|
||||
let mut transformed = Cow::Borrowed(contents);
|
||||
@@ -387,8 +389,8 @@ pub fn lint_fix<'a>(
|
||||
&indexer,
|
||||
&directives,
|
||||
settings,
|
||||
noqa,
|
||||
flags::Autofix::Enabled,
|
||||
flags::Noqa::Enabled,
|
||||
);
|
||||
|
||||
if iterations == 0 {
|
||||
|
||||
@@ -59,6 +59,10 @@ ruff_macros::register_rules!(
|
||||
#[cfg(feature = "logical_lines")]
|
||||
rules::pycodestyle::rules::TabAfterKeyword,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
rules::pycodestyle::rules::UnexpectedSpacesAroundKeywordParameterEquals,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
rules::pycodestyle::rules::MissingWhitespaceAroundParameterEquals,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
rules::pycodestyle::rules::TabBeforeKeyword,
|
||||
rules::pycodestyle::rules::MultipleImportsOnOneLine,
|
||||
rules::pycodestyle::rules::ModuleImportNotAtTopOfFile,
|
||||
@@ -79,6 +83,7 @@ ruff_macros::register_rules!(
|
||||
rules::pycodestyle::rules::IOError,
|
||||
rules::pycodestyle::rules::SyntaxError,
|
||||
// pycodestyle warnings
|
||||
rules::pycodestyle::rules::IndentationContainsTabs,
|
||||
rules::pycodestyle::rules::TrailingWhitespace,
|
||||
rules::pycodestyle::rules::NoNewLineAtEndOfFile,
|
||||
rules::pycodestyle::rules::BlankLineContainsWhitespace,
|
||||
@@ -326,6 +331,7 @@ ruff_macros::register_rules!(
|
||||
rules::pyupgrade::rules::ImportReplacements,
|
||||
rules::pyupgrade::rules::OutdatedVersionBlock,
|
||||
rules::pyupgrade::rules::QuotedAnnotation,
|
||||
rules::pyupgrade::rules::IsinstanceWithTuple,
|
||||
// pydocstyle
|
||||
rules::pydocstyle::rules::PublicModule,
|
||||
rules::pydocstyle::rules::PublicClass,
|
||||
@@ -461,6 +467,7 @@ ruff_macros::register_rules!(
|
||||
rules::flake8_errmsg::rules::DotFormatInException,
|
||||
// flake8-pyi
|
||||
rules::flake8_pyi::rules::PrefixTypeParams,
|
||||
rules::flake8_pyi::rules::BadVersionInfoComparison,
|
||||
rules::flake8_pyi::rules::UnrecognizedPlatformCheck,
|
||||
rules::flake8_pyi::rules::UnrecognizedPlatformName,
|
||||
rules::flake8_pyi::rules::PassStatementStubBody,
|
||||
@@ -577,7 +584,6 @@ ruff_macros::register_rules!(
|
||||
rules::ruff::rules::AmbiguousUnicodeCharacterString,
|
||||
rules::ruff::rules::AmbiguousUnicodeCharacterDocstring,
|
||||
rules::ruff::rules::AmbiguousUnicodeCharacterComment,
|
||||
rules::ruff::rules::KeywordArgumentBeforeStarArgument,
|
||||
rules::ruff::rules::UnpackInsteadOfConcatenatingToCollectionLiteral,
|
||||
rules::ruff::rules::AsyncioDanglingTask,
|
||||
rules::ruff::rules::UnusedNOQA,
|
||||
@@ -803,6 +809,7 @@ impl Rule {
|
||||
| Rule::ShebangPython
|
||||
| Rule::ShebangWhitespace
|
||||
| Rule::TrailingWhitespace
|
||||
| Rule::IndentationContainsTabs
|
||||
| Rule::BlankLineContainsWhitespace => &LintSource::PhysicalLines,
|
||||
Rule::AmbiguousUnicodeCharacterComment
|
||||
| Rule::AmbiguousUnicodeCharacterDocstring
|
||||
@@ -848,6 +855,8 @@ impl Rule {
|
||||
| Rule::UnexpectedIndentationComment
|
||||
| Rule::WhitespaceAfterOpenBracket
|
||||
| Rule::WhitespaceBeforeCloseBracket
|
||||
| Rule::UnexpectedSpacesAroundKeywordParameterEquals
|
||||
| Rule::MissingWhitespaceAroundParameterEquals
|
||||
| Rule::WhitespaceBeforePunctuation => &LintSource::LogicalLines,
|
||||
_ => &LintSource::Ast,
|
||||
}
|
||||
|
||||
@@ -92,5 +92,7 @@ static REDIRECTS: Lazy<HashMap<&'static str, &'static str>> = Lazy::new(|| {
|
||||
// TODO(charlie): Remove by 2023-04-01.
|
||||
("TYP", "TCH"),
|
||||
("TYP001", "TCH001"),
|
||||
// TODO(charlie): Remove by 2023-06-01.
|
||||
("RUF004", "B026"),
|
||||
])
|
||||
});
|
||||
|
||||
@@ -398,9 +398,9 @@ define_violation!(
|
||||
/// ```
|
||||
///
|
||||
/// ## References
|
||||
/// * [PEP 484](https://www.python.org/dev/peps/pep-0484/#the-any-type)
|
||||
/// * [`typing.Any`](https://docs.python.org/3/library/typing.html#typing.Any)
|
||||
/// * [Mypy: The Any type](https://mypy.readthedocs.io/en/stable/kinds_of_types.html#the-any-type)
|
||||
/// - [PEP 484](https://www.python.org/dev/peps/pep-0484/#the-any-type)
|
||||
/// - [`typing.Any`](https://docs.python.org/3/library/typing.html#typing.Any)
|
||||
/// - [Mypy: The Any type](https://mypy.readthedocs.io/en/stable/kinds_of_types.html#the-any-type)
|
||||
pub struct AnyType {
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
@@ -37,8 +37,8 @@ pub struct Options {
|
||||
/// Whether to suppress `ANN200`-level violations for functions that meet
|
||||
/// either of the following criteria:
|
||||
///
|
||||
/// * Contain no `return` statement.
|
||||
/// * Explicit `return` statement(s) all return `None` (explicitly or
|
||||
/// - Contain no `return` statement.
|
||||
/// - Explicit `return` statement(s) all return `None` (explicitly or
|
||||
/// implicitly).
|
||||
pub suppress_none_returning: Option<bool>,
|
||||
#[option(
|
||||
|
||||
@@ -4,8 +4,9 @@ use rustpython_parser::ast::{Constant, Expr, ExprKind};
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
|
||||
static PASSWORD_CANDIDATE_REGEX: Lazy<Regex> =
|
||||
Lazy::new(|| Regex::new(r"(^|_)(pas+wo?r?d|pass(phrase)?|pwd|token|secrete?)($|_)").unwrap());
|
||||
static PASSWORD_CANDIDATE_REGEX: Lazy<Regex> = Lazy::new(|| {
|
||||
Regex::new(r"(^|_)(?i)(pas+wo?r?d|pass(phrase)?|pwd|token|secrete?)($|_)").unwrap()
|
||||
});
|
||||
|
||||
pub fn string_literal(expr: &Expr) -> Option<&str> {
|
||||
match &expr.node {
|
||||
@@ -17,7 +18,6 @@ pub fn string_literal(expr: &Expr) -> Option<&str> {
|
||||
}
|
||||
}
|
||||
|
||||
// Maybe use regex for this?
|
||||
pub fn matches_password_name(string: &str) -> bool {
|
||||
PASSWORD_CANDIDATE_REGEX.is_match(string)
|
||||
}
|
||||
|
||||
@@ -33,8 +33,8 @@ define_violation!(
|
||||
/// ```
|
||||
///
|
||||
/// ## References
|
||||
/// * [B608: Test for SQL injection](https://bandit.readthedocs.io/en/latest/plugins/b608_hardcoded_sql_expressions.html)
|
||||
/// * [psycopg3: Server-side binding](https://www.psycopg.org/psycopg3/docs/basic/from_pg2.html#server-side-binding)
|
||||
/// - [B608: Test for SQL injection](https://bandit.readthedocs.io/en/latest/plugins/b608_hardcoded_sql_expressions.html)
|
||||
/// - [psycopg3: Server-side binding](https://www.psycopg.org/psycopg3/docs/basic/from_pg2.html#server-side-binding)
|
||||
pub struct HardcodedSQLExpression;
|
||||
);
|
||||
impl Violation for HardcodedSQLExpression {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
source: src/rules/flake8_bandit/mod.rs
|
||||
source: crates/ruff/src/rules/flake8_bandit/mod.rs
|
||||
expression: diagnostics
|
||||
---
|
||||
- kind:
|
||||
@@ -105,46 +105,46 @@ expression: diagnostics
|
||||
HardcodedPasswordString:
|
||||
string: s3cr3t
|
||||
location:
|
||||
row: 23
|
||||
column: 16
|
||||
end_location:
|
||||
row: 23
|
||||
column: 24
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
HardcodedPasswordString:
|
||||
string: s3cr3t
|
||||
location:
|
||||
row: 24
|
||||
column: 12
|
||||
end_location:
|
||||
row: 24
|
||||
column: 20
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
HardcodedPasswordString:
|
||||
string: s3cr3t
|
||||
location:
|
||||
row: 25
|
||||
column: 14
|
||||
end_location:
|
||||
row: 25
|
||||
column: 22
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
HardcodedPasswordString:
|
||||
string: s3cr3t
|
||||
location:
|
||||
row: 26
|
||||
row: 22
|
||||
column: 11
|
||||
end_location:
|
||||
row: 26
|
||||
row: 22
|
||||
column: 19
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
HardcodedPasswordString:
|
||||
string: s3cr3t
|
||||
location:
|
||||
row: 23
|
||||
column: 11
|
||||
end_location:
|
||||
row: 23
|
||||
column: 19
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
HardcodedPasswordString:
|
||||
string: s3cr3t
|
||||
location:
|
||||
row: 25
|
||||
column: 16
|
||||
end_location:
|
||||
row: 25
|
||||
column: 24
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
HardcodedPasswordString:
|
||||
string: s3cr3t
|
||||
location:
|
||||
row: 26
|
||||
column: 12
|
||||
end_location:
|
||||
row: 26
|
||||
column: 20
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
HardcodedPasswordString:
|
||||
string: s3cr3t
|
||||
@@ -161,9 +161,31 @@ expression: diagnostics
|
||||
string: s3cr3t
|
||||
location:
|
||||
row: 28
|
||||
column: 13
|
||||
column: 11
|
||||
end_location:
|
||||
row: 28
|
||||
column: 19
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
HardcodedPasswordString:
|
||||
string: s3cr3t
|
||||
location:
|
||||
row: 29
|
||||
column: 14
|
||||
end_location:
|
||||
row: 29
|
||||
column: 22
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
HardcodedPasswordString:
|
||||
string: s3cr3t
|
||||
location:
|
||||
row: 30
|
||||
column: 13
|
||||
end_location:
|
||||
row: 30
|
||||
column: 21
|
||||
fix: ~
|
||||
parent: ~
|
||||
@@ -171,10 +193,10 @@ expression: diagnostics
|
||||
HardcodedPasswordString:
|
||||
string: s3cr3t
|
||||
location:
|
||||
row: 29
|
||||
row: 31
|
||||
column: 15
|
||||
end_location:
|
||||
row: 29
|
||||
row: 31
|
||||
column: 23
|
||||
fix: ~
|
||||
parent: ~
|
||||
@@ -182,10 +204,10 @@ expression: diagnostics
|
||||
HardcodedPasswordString:
|
||||
string: s3cr3t
|
||||
location:
|
||||
row: 30
|
||||
row: 32
|
||||
column: 23
|
||||
end_location:
|
||||
row: 30
|
||||
row: 32
|
||||
column: 31
|
||||
fix: ~
|
||||
parent: ~
|
||||
@@ -193,10 +215,10 @@ expression: diagnostics
|
||||
HardcodedPasswordString:
|
||||
string: s3cr3t
|
||||
location:
|
||||
row: 31
|
||||
row: 33
|
||||
column: 23
|
||||
end_location:
|
||||
row: 31
|
||||
row: 33
|
||||
column: 31
|
||||
fix: ~
|
||||
parent: ~
|
||||
@@ -204,10 +226,10 @@ expression: diagnostics
|
||||
HardcodedPasswordString:
|
||||
string: s3cr3t
|
||||
location:
|
||||
row: 35
|
||||
row: 37
|
||||
column: 15
|
||||
end_location:
|
||||
row: 35
|
||||
row: 37
|
||||
column: 23
|
||||
fix: ~
|
||||
parent: ~
|
||||
@@ -215,10 +237,10 @@ expression: diagnostics
|
||||
HardcodedPasswordString:
|
||||
string: s3cr3t
|
||||
location:
|
||||
row: 39
|
||||
row: 41
|
||||
column: 19
|
||||
end_location:
|
||||
row: 39
|
||||
row: 41
|
||||
column: 27
|
||||
fix: ~
|
||||
parent: ~
|
||||
@@ -226,10 +248,10 @@ expression: diagnostics
|
||||
HardcodedPasswordString:
|
||||
string: s3cr3t
|
||||
location:
|
||||
row: 40
|
||||
row: 42
|
||||
column: 16
|
||||
end_location:
|
||||
row: 40
|
||||
row: 42
|
||||
column: 24
|
||||
fix: ~
|
||||
parent: ~
|
||||
@@ -237,10 +259,10 @@ expression: diagnostics
|
||||
HardcodedPasswordString:
|
||||
string: s3cr3t
|
||||
location:
|
||||
row: 41
|
||||
row: 43
|
||||
column: 17
|
||||
end_location:
|
||||
row: 41
|
||||
row: 43
|
||||
column: 25
|
||||
fix: ~
|
||||
parent: ~
|
||||
@@ -248,10 +270,10 @@ expression: diagnostics
|
||||
HardcodedPasswordString:
|
||||
string: s3cr3t
|
||||
location:
|
||||
row: 42
|
||||
row: 44
|
||||
column: 14
|
||||
end_location:
|
||||
row: 42
|
||||
row: 44
|
||||
column: 22
|
||||
fix: ~
|
||||
parent: ~
|
||||
@@ -259,10 +281,10 @@ expression: diagnostics
|
||||
HardcodedPasswordString:
|
||||
string: s3cr3t
|
||||
location:
|
||||
row: 43
|
||||
row: 45
|
||||
column: 17
|
||||
end_location:
|
||||
row: 43
|
||||
row: 45
|
||||
column: 25
|
||||
fix: ~
|
||||
parent: ~
|
||||
@@ -270,10 +292,10 @@ expression: diagnostics
|
||||
HardcodedPasswordString:
|
||||
string: s3cr3t
|
||||
location:
|
||||
row: 44
|
||||
row: 46
|
||||
column: 16
|
||||
end_location:
|
||||
row: 44
|
||||
row: 46
|
||||
column: 24
|
||||
fix: ~
|
||||
parent: ~
|
||||
@@ -281,10 +303,10 @@ expression: diagnostics
|
||||
HardcodedPasswordString:
|
||||
string: s3cr3t
|
||||
location:
|
||||
row: 45
|
||||
row: 47
|
||||
column: 18
|
||||
end_location:
|
||||
row: 45
|
||||
row: 47
|
||||
column: 26
|
||||
fix: ~
|
||||
parent: ~
|
||||
@@ -292,10 +314,10 @@ expression: diagnostics
|
||||
HardcodedPasswordString:
|
||||
string: s3cr3t
|
||||
location:
|
||||
row: 47
|
||||
row: 49
|
||||
column: 12
|
||||
end_location:
|
||||
row: 47
|
||||
row: 49
|
||||
column: 20
|
||||
fix: ~
|
||||
parent: ~
|
||||
@@ -303,10 +325,10 @@ expression: diagnostics
|
||||
HardcodedPasswordString:
|
||||
string: s3cr3t
|
||||
location:
|
||||
row: 48
|
||||
row: 50
|
||||
column: 9
|
||||
end_location:
|
||||
row: 48
|
||||
row: 50
|
||||
column: 17
|
||||
fix: ~
|
||||
parent: ~
|
||||
@@ -314,10 +336,10 @@ expression: diagnostics
|
||||
HardcodedPasswordString:
|
||||
string: s3cr3t
|
||||
location:
|
||||
row: 49
|
||||
row: 51
|
||||
column: 10
|
||||
end_location:
|
||||
row: 49
|
||||
row: 51
|
||||
column: 18
|
||||
fix: ~
|
||||
parent: ~
|
||||
@@ -325,10 +347,10 @@ expression: diagnostics
|
||||
HardcodedPasswordString:
|
||||
string: s3cr3t
|
||||
location:
|
||||
row: 50
|
||||
row: 52
|
||||
column: 7
|
||||
end_location:
|
||||
row: 50
|
||||
row: 52
|
||||
column: 15
|
||||
fix: ~
|
||||
parent: ~
|
||||
@@ -336,10 +358,10 @@ expression: diagnostics
|
||||
HardcodedPasswordString:
|
||||
string: s3cr3t
|
||||
location:
|
||||
row: 51
|
||||
row: 53
|
||||
column: 10
|
||||
end_location:
|
||||
row: 51
|
||||
row: 53
|
||||
column: 18
|
||||
fix: ~
|
||||
parent: ~
|
||||
@@ -347,10 +369,10 @@ expression: diagnostics
|
||||
HardcodedPasswordString:
|
||||
string: s3cr3t
|
||||
location:
|
||||
row: 52
|
||||
row: 54
|
||||
column: 9
|
||||
end_location:
|
||||
row: 52
|
||||
row: 54
|
||||
column: 17
|
||||
fix: ~
|
||||
parent: ~
|
||||
@@ -358,10 +380,10 @@ expression: diagnostics
|
||||
HardcodedPasswordString:
|
||||
string: s3cr3t
|
||||
location:
|
||||
row: 53
|
||||
row: 55
|
||||
column: 11
|
||||
end_location:
|
||||
row: 53
|
||||
row: 55
|
||||
column: 19
|
||||
fix: ~
|
||||
parent: ~
|
||||
@@ -369,10 +391,10 @@ expression: diagnostics
|
||||
HardcodedPasswordString:
|
||||
string: s3cr3t
|
||||
location:
|
||||
row: 54
|
||||
row: 56
|
||||
column: 20
|
||||
end_location:
|
||||
row: 54
|
||||
row: 56
|
||||
column: 28
|
||||
fix: ~
|
||||
parent: ~
|
||||
@@ -380,10 +402,10 @@ expression: diagnostics
|
||||
HardcodedPasswordString:
|
||||
string: "1\n2"
|
||||
location:
|
||||
row: 56
|
||||
row: 58
|
||||
column: 12
|
||||
end_location:
|
||||
row: 56
|
||||
row: 58
|
||||
column: 18
|
||||
fix: ~
|
||||
parent: ~
|
||||
@@ -391,10 +413,10 @@ expression: diagnostics
|
||||
HardcodedPasswordString:
|
||||
string: "3\t4"
|
||||
location:
|
||||
row: 59
|
||||
row: 61
|
||||
column: 12
|
||||
end_location:
|
||||
row: 59
|
||||
row: 61
|
||||
column: 18
|
||||
fix: ~
|
||||
parent: ~
|
||||
@@ -402,10 +424,10 @@ expression: diagnostics
|
||||
HardcodedPasswordString:
|
||||
string: "5\r6"
|
||||
location:
|
||||
row: 62
|
||||
row: 64
|
||||
column: 12
|
||||
end_location:
|
||||
row: 62
|
||||
row: 64
|
||||
column: 18
|
||||
fix: ~
|
||||
parent: ~
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
use rustpython_parser::ast::{ExprKind, Stmt};
|
||||
|
||||
use ruff_macros::{define_violation, derive_message_formats};
|
||||
use ruff_python::str::is_lower;
|
||||
use rustpython_parser::ast::{ExprKind, Stmt, StmtKind};
|
||||
|
||||
use crate::ast::types::Range;
|
||||
use crate::ast::helpers::RaiseStatementVisitor;
|
||||
use crate::ast::visitor;
|
||||
use crate::ast::visitor::Visitor;
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::registry::Diagnostic;
|
||||
use crate::violation::Violation;
|
||||
@@ -16,62 +16,32 @@ impl Violation for RaiseWithoutFromInsideExcept {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!(
|
||||
"Within an except clause, raise exceptions with `raise ... from err` or `raise ... \
|
||||
"Within an `except` clause, raise exceptions with `raise ... from err` or `raise ... \
|
||||
from None` to distinguish them from errors in exception handling"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
struct RaiseVisitor {
|
||||
diagnostics: Vec<Diagnostic>,
|
||||
}
|
||||
/// B904
|
||||
pub fn raise_without_from_inside_except(checker: &mut Checker, body: &[Stmt]) {
|
||||
let raises = {
|
||||
let mut visitor = RaiseStatementVisitor::default();
|
||||
visitor::walk_body(&mut visitor, body);
|
||||
visitor.raises
|
||||
};
|
||||
|
||||
impl<'a> Visitor<'a> for RaiseVisitor {
|
||||
fn visit_stmt(&mut self, stmt: &'a Stmt) {
|
||||
match &stmt.node {
|
||||
StmtKind::Raise {
|
||||
exc: Some(exc),
|
||||
cause: None,
|
||||
} => match &exc.node {
|
||||
ExprKind::Name { id, .. } if is_lower(id) => {}
|
||||
_ => {
|
||||
self.diagnostics.push(Diagnostic::new(
|
||||
RaiseWithoutFromInsideExcept,
|
||||
Range::from_located(stmt),
|
||||
));
|
||||
}
|
||||
},
|
||||
StmtKind::ClassDef { .. }
|
||||
| StmtKind::FunctionDef { .. }
|
||||
| StmtKind::AsyncFunctionDef { .. }
|
||||
| StmtKind::Try { .. }
|
||||
| StmtKind::TryStar { .. } => {}
|
||||
StmtKind::If { body, orelse, .. } => {
|
||||
visitor::walk_body(self, body);
|
||||
visitor::walk_body(self, orelse);
|
||||
}
|
||||
StmtKind::While { body, .. }
|
||||
| StmtKind::With { body, .. }
|
||||
| StmtKind::AsyncWith { body, .. }
|
||||
| StmtKind::For { body, .. }
|
||||
| StmtKind::AsyncFor { body, .. } => {
|
||||
visitor::walk_body(self, body);
|
||||
}
|
||||
StmtKind::Match { cases, .. } => {
|
||||
for case in cases {
|
||||
visitor::walk_body(self, &case.body);
|
||||
for (range, exc, cause) in raises {
|
||||
if cause.is_none() {
|
||||
if let Some(exc) = exc {
|
||||
match &exc.node {
|
||||
ExprKind::Name { id, .. } if is_lower(id) => {}
|
||||
_ => {
|
||||
checker
|
||||
.diagnostics
|
||||
.push(Diagnostic::new(RaiseWithoutFromInsideExcept, range));
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// B904
|
||||
pub fn raise_without_from_inside_except(checker: &mut Checker, body: &[Stmt]) {
|
||||
let mut visitor = RaiseVisitor {
|
||||
diagnostics: vec![],
|
||||
};
|
||||
visitor::walk_body(&mut visitor, body);
|
||||
checker.diagnostics.extend(visitor.diagnostics);
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ define_violation!(
|
||||
///
|
||||
/// ## Options
|
||||
///
|
||||
/// * `flake8-builtins.builtins-ignorelist`
|
||||
/// - `flake8-builtins.builtins-ignorelist`
|
||||
///
|
||||
/// ## Example
|
||||
/// ```python
|
||||
@@ -45,7 +45,7 @@ define_violation!(
|
||||
/// return result
|
||||
/// ```
|
||||
///
|
||||
/// * [Why is it a bad idea to name a variable `id` in Python?_](https://stackoverflow.com/questions/77552/id-is-a-bad-variable-name-in-python)
|
||||
/// - [_Why is it a bad idea to name a variable `id` in Python?_](https://stackoverflow.com/questions/77552/id-is-a-bad-variable-name-in-python)
|
||||
pub struct BuiltinVariableShadowing {
|
||||
pub name: String,
|
||||
}
|
||||
@@ -73,7 +73,7 @@ define_violation!(
|
||||
///
|
||||
/// ## Options
|
||||
///
|
||||
/// * `flake8-builtins.builtins-ignorelist`
|
||||
/// - `flake8-builtins.builtins-ignorelist`
|
||||
///
|
||||
/// ## Example
|
||||
/// ```python
|
||||
@@ -128,7 +128,7 @@ define_violation!(
|
||||
///
|
||||
/// ## Options
|
||||
///
|
||||
/// * `flake8-builtins.builtins-ignorelist`
|
||||
/// - `flake8-builtins.builtins-ignorelist`
|
||||
///
|
||||
/// ## Example
|
||||
/// ```python
|
||||
|
||||
@@ -32,19 +32,19 @@ define_violation!(
|
||||
///
|
||||
/// This rule applies to a variety of functions, including `list`, `reversed`,
|
||||
/// `set`, `sorted`, and `tuple`. For example:
|
||||
/// * Instead of `list(list(iterable))`, use `list(iterable)`.
|
||||
/// * Instead of `list(tuple(iterable))`, use `list(iterable)`.
|
||||
/// * Instead of `tuple(list(iterable))`, use `tuple(iterable)`.
|
||||
/// * Instead of `tuple(tuple(iterable))`, use `tuple(iterable)`.
|
||||
/// * Instead of `set(set(iterable))`, use `set(iterable)`.
|
||||
/// * Instead of `set(list(iterable))`, use `set(iterable)`.
|
||||
/// * Instead of `set(tuple(iterable))`, use `set(iterable)`.
|
||||
/// * Instead of `set(sorted(iterable))`, use `set(iterable)`.
|
||||
/// * Instead of `set(reversed(iterable))`, use `set(iterable)`.
|
||||
/// * Instead of `sorted(list(iterable))`, use `sorted(iterable)`.
|
||||
/// * Instead of `sorted(tuple(iterable))`, use `sorted(iterable)`.
|
||||
/// * Instead of `sorted(sorted(iterable))`, use `sorted(iterable)`.
|
||||
/// * Instead of `sorted(reversed(iterable))`, use `sorted(iterable)`.
|
||||
/// - Instead of `list(list(iterable))`, use `list(iterable)`.
|
||||
/// - Instead of `list(tuple(iterable))`, use `list(iterable)`.
|
||||
/// - Instead of `tuple(list(iterable))`, use `tuple(iterable)`.
|
||||
/// - Instead of `tuple(tuple(iterable))`, use `tuple(iterable)`.
|
||||
/// - Instead of `set(set(iterable))`, use `set(iterable)`.
|
||||
/// - Instead of `set(list(iterable))`, use `set(iterable)`.
|
||||
/// - Instead of `set(tuple(iterable))`, use `set(iterable)`.
|
||||
/// - Instead of `set(sorted(iterable))`, use `set(iterable)`.
|
||||
/// - Instead of `set(reversed(iterable))`, use `set(iterable)`.
|
||||
/// - Instead of `sorted(list(iterable))`, use `sorted(iterable)`.
|
||||
/// - Instead of `sorted(tuple(iterable))`, use `sorted(iterable)`.
|
||||
/// - Instead of `sorted(sorted(iterable))`, use `sorted(iterable)`.
|
||||
/// - Instead of `sorted(reversed(iterable))`, use `sorted(iterable)`.
|
||||
pub struct UnnecessaryDoubleCastOrProcess {
|
||||
pub inner: String,
|
||||
pub outer: String,
|
||||
|
||||
@@ -32,11 +32,11 @@ define_violation!(
|
||||
///
|
||||
/// This rule also applies to `map` calls within `list`, `set`, and `dict`
|
||||
/// calls. For example:
|
||||
/// * Instead of `list(map(lambda num: num * 2, nums))`, use
|
||||
/// - Instead of `list(map(lambda num: num * 2, nums))`, use
|
||||
/// `[num * 2 for num in nums]`.
|
||||
/// * Instead of `set(map(lambda num: num % 2 == 0, nums))`, use
|
||||
/// - Instead of `set(map(lambda num: num % 2 == 0, nums))`, use
|
||||
/// `{num % 2 == 0 for num in nums}`.
|
||||
/// * Instead of `dict(map(lambda v: (v, v ** 2), values))`, use
|
||||
/// - Instead of `dict(map(lambda v: (v, v ** 2), values))`, use
|
||||
/// `{v: v ** 2 for v in values}`.
|
||||
pub struct UnnecessaryMap {
|
||||
pub obj_type: String,
|
||||
|
||||
@@ -20,6 +20,7 @@ define_violation!(
|
||||
/// ```python
|
||||
/// from django.forms import ModelForm
|
||||
///
|
||||
///
|
||||
/// class PostForm(ModelForm):
|
||||
/// class Meta:
|
||||
/// model = Post
|
||||
@@ -30,6 +31,7 @@ define_violation!(
|
||||
/// ```python
|
||||
/// from django.forms import ModelForm
|
||||
///
|
||||
///
|
||||
/// class PostForm(ModelForm):
|
||||
/// class Meta:
|
||||
/// model = Post
|
||||
|
||||
@@ -26,19 +26,21 @@ define_violation!(
|
||||
/// ```python
|
||||
/// from django.db import models
|
||||
///
|
||||
///
|
||||
/// class MyModel(models.Model):
|
||||
/// field = models.CharField(max_length=255)
|
||||
/// field = models.CharField(max_length=255)
|
||||
/// ```
|
||||
///
|
||||
/// Use instead:
|
||||
/// ```python
|
||||
/// from django.db import models
|
||||
///
|
||||
/// class MyModel(models.Model):
|
||||
/// field = models.CharField(max_length=255)
|
||||
///
|
||||
/// def __str__(self):
|
||||
/// return f"{self.field}"
|
||||
/// class MyModel(models.Model):
|
||||
/// field = models.CharField(max_length=255)
|
||||
///
|
||||
/// def __str__(self):
|
||||
/// return f"{self.field}"
|
||||
/// ```
|
||||
pub struct ModelWithoutDunderStr;
|
||||
);
|
||||
|
||||
@@ -22,10 +22,11 @@ define_violation!(
|
||||
/// from django.dispatch import receiver
|
||||
/// from django.db.models.signals import post_save
|
||||
///
|
||||
///
|
||||
/// @transaction.atomic
|
||||
/// @receiver(post_save, sender=MyModel)
|
||||
/// def my_handler(sender, instance, created, **kwargs):
|
||||
/// pass
|
||||
/// pass
|
||||
/// ```
|
||||
///
|
||||
/// Use instead:
|
||||
@@ -33,6 +34,7 @@ define_violation!(
|
||||
/// from django.dispatch import receiver
|
||||
/// from django.db.models.signals import post_save
|
||||
///
|
||||
///
|
||||
/// @receiver(post_save, sender=MyModel)
|
||||
/// @transaction.atomic
|
||||
/// def my_handler(sender, instance, created, **kwargs):
|
||||
|
||||
@@ -28,14 +28,16 @@ define_violation!(
|
||||
/// ```python
|
||||
/// from django.db import models
|
||||
///
|
||||
///
|
||||
/// class MyModel(models.Model):
|
||||
/// field = models.CharField(max_length=255, null=True)
|
||||
/// field = models.CharField(max_length=255, null=True)
|
||||
/// ```
|
||||
///
|
||||
/// Use instead:
|
||||
/// ```python
|
||||
/// from django.db import models
|
||||
///
|
||||
///
|
||||
/// class MyModel(models.Model):
|
||||
/// field = models.CharField(max_length=255, default="")
|
||||
/// ```
|
||||
|
||||
@@ -24,7 +24,7 @@ define_violation!(
|
||||
/// ```
|
||||
///
|
||||
/// Python will produce a traceback like:
|
||||
/// ```python
|
||||
/// ```console
|
||||
/// Traceback (most recent call last):
|
||||
/// File "tmp.py", line 2, in <module>
|
||||
/// raise RuntimeError("Some value is incorrect")
|
||||
@@ -38,7 +38,7 @@ define_violation!(
|
||||
/// ```
|
||||
///
|
||||
/// Which will produce a traceback like:
|
||||
/// ```python
|
||||
/// ```console
|
||||
/// Traceback (most recent call last):
|
||||
/// File "tmp.py", line 3, in <module>
|
||||
/// raise RuntimeError(msg)
|
||||
@@ -72,7 +72,7 @@ define_violation!(
|
||||
/// ```
|
||||
///
|
||||
/// Python will produce a traceback like:
|
||||
/// ```python
|
||||
/// ```console
|
||||
/// Traceback (most recent call last):
|
||||
/// File "tmp.py", line 2, in <module>
|
||||
/// raise RuntimeError(f"{sub!r} is incorrect")
|
||||
@@ -87,8 +87,7 @@ define_violation!(
|
||||
/// ```
|
||||
///
|
||||
/// Which will produce a traceback like:
|
||||
/// ```python
|
||||
/// Traceback (most recent call last):
|
||||
/// ```console
|
||||
/// File "tmp.py", line 3, in <module>
|
||||
/// raise RuntimeError(msg)
|
||||
/// RuntimeError: 'Some value' is incorrect
|
||||
@@ -122,7 +121,7 @@ define_violation!(
|
||||
/// ```
|
||||
///
|
||||
/// Python will produce a traceback like:
|
||||
/// ```python
|
||||
/// ```console
|
||||
/// Traceback (most recent call last):
|
||||
/// File "tmp.py", line 2, in <module>
|
||||
/// raise RuntimeError("'{}' is incorrect".format(sub))
|
||||
@@ -137,7 +136,7 @@ define_violation!(
|
||||
/// ```
|
||||
///
|
||||
/// Which will produce a traceback like:
|
||||
/// ```python
|
||||
/// ```console
|
||||
/// Traceback (most recent call last):
|
||||
/// File "tmp.py", line 3, in <module>
|
||||
/// raise RuntimeError(msg)
|
||||
|
||||
@@ -56,7 +56,7 @@ define_violation!(
|
||||
/// to `false`.
|
||||
///
|
||||
/// ## Options
|
||||
/// * `flake8-implicit-str-concat.allow-multiline`
|
||||
/// - `flake8-implicit-str-concat.allow-multiline`
|
||||
///
|
||||
/// ## Example
|
||||
/// ```python
|
||||
@@ -73,7 +73,7 @@ define_violation!(
|
||||
/// ```
|
||||
///
|
||||
/// ## References
|
||||
/// * [PEP 8](https://peps.python.org/pep-0008/#maximum-line-length)
|
||||
/// - [PEP 8](https://peps.python.org/pep-0008/#maximum-line-length)
|
||||
pub struct MultiLineImplicitStringConcatenation;
|
||||
);
|
||||
impl Violation for MultiLineImplicitStringConcatenation {
|
||||
|
||||
@@ -25,7 +25,7 @@ define_violation!(
|
||||
/// the absence of the `__init__.py` file is probably an oversight.
|
||||
///
|
||||
/// ## Options
|
||||
/// * `namespace-packages`
|
||||
/// - `namespace-packages`
|
||||
pub struct ImplicitNamespacePackage {
|
||||
pub filename: String,
|
||||
}
|
||||
|
||||
@@ -72,7 +72,7 @@ define_violation!(
|
||||
/// For example, compare the performance of `all` with a list comprehension against that
|
||||
/// of a generator (~40x faster here):
|
||||
///
|
||||
/// ```python
|
||||
/// ```console
|
||||
/// In [1]: %timeit all([i for i in range(1000)])
|
||||
/// 8.14 µs ± 25.4 ns per loop (mean ± std. dev. of 7 runs, 100,000 loops each)
|
||||
///
|
||||
|
||||
@@ -15,6 +15,8 @@ mod tests {
|
||||
|
||||
#[test_case(Rule::PrefixTypeParams, Path::new("PYI001.pyi"))]
|
||||
#[test_case(Rule::PrefixTypeParams, Path::new("PYI001.py"))]
|
||||
#[test_case(Rule::BadVersionInfoComparison, Path::new("PYI006.pyi"))]
|
||||
#[test_case(Rule::BadVersionInfoComparison, Path::new("PYI006.py"))]
|
||||
#[test_case(Rule::UnrecognizedPlatformCheck, Path::new("PYI007.pyi"))]
|
||||
#[test_case(Rule::UnrecognizedPlatformCheck, Path::new("PYI007.py"))]
|
||||
#[test_case(Rule::UnrecognizedPlatformName, Path::new("PYI008.pyi"))]
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
use rustpython_parser::ast::{Cmpop, Expr};
|
||||
|
||||
use ruff_macros::{define_violation, derive_message_formats};
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::registry::Diagnostic;
|
||||
use crate::violation::Violation;
|
||||
use crate::Range;
|
||||
|
||||
define_violation!(
|
||||
/// ## What it does
|
||||
/// Checks for usages of comparators other than `<` and `>=` for
|
||||
/// `sys.version_info` checks in `.pyi` files. All other comparators, such
|
||||
/// as `>`, `<=`, and `==`, are banned.
|
||||
///
|
||||
/// ## Why is this bad?
|
||||
/// Comparing `sys.version_info` with `==` or `<=` has unexpected behavior
|
||||
/// and can lead to bugs.
|
||||
///
|
||||
/// For example, `sys.version_info > (3, 8)` will also match `3.8.10`,
|
||||
/// while `sys.version_info <= (3, 8)` will _not_ match `3.8.10`:
|
||||
///
|
||||
/// ```python
|
||||
/// >>> import sys
|
||||
/// >>> print(sys.version_info)
|
||||
/// sys.version_info(major=3, minor=8, micro=10, releaselevel='final', serial=0)
|
||||
/// >>> print(sys.version_info > (3, 8))
|
||||
/// True
|
||||
/// >>> print(sys.version_info == (3, 8))
|
||||
/// False
|
||||
/// >>> print(sys.version_info <= (3, 8))
|
||||
/// False
|
||||
/// >>> print(sys.version_info in (3, 8))
|
||||
/// False
|
||||
/// ```
|
||||
///
|
||||
/// ## Example
|
||||
/// ```python
|
||||
/// import sys
|
||||
///
|
||||
/// if sys.version_info > (3, 8):
|
||||
/// ...
|
||||
/// ```
|
||||
///
|
||||
/// Use instead:
|
||||
/// ```python
|
||||
/// import sys
|
||||
///
|
||||
/// if sys.version_info >= (3, 9):
|
||||
/// ...
|
||||
/// ```
|
||||
pub struct BadVersionInfoComparison;
|
||||
);
|
||||
impl Violation for BadVersionInfoComparison {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!("Use `<` or `>=` for version info comparisons")
|
||||
}
|
||||
}
|
||||
|
||||
/// PYI006
|
||||
pub fn bad_version_info_comparison(
|
||||
checker: &mut Checker,
|
||||
expr: &Expr,
|
||||
left: &Expr,
|
||||
ops: &[Cmpop],
|
||||
comparators: &[Expr],
|
||||
) {
|
||||
let ([op], [_right]) = (ops, comparators) else {
|
||||
return;
|
||||
};
|
||||
|
||||
if !checker.resolve_call_path(left).map_or(false, |call_path| {
|
||||
call_path.as_slice() == ["sys", "version_info"]
|
||||
}) {
|
||||
return;
|
||||
}
|
||||
|
||||
if !matches!(op, Cmpop::Lt | Cmpop::GtE) {
|
||||
let diagnostic = Diagnostic::new(BadVersionInfoComparison, Range::from_located(expr));
|
||||
checker.diagnostics.push(diagnostic);
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
pub use bad_version_info_comparison::{bad_version_info_comparison, BadVersionInfoComparison};
|
||||
pub use docstring_in_stubs::{docstring_in_stubs, DocstringInStub};
|
||||
pub use non_empty_stub_body::{non_empty_stub_body, NonEmptyStubBody};
|
||||
pub use pass_statement_stub_body::{pass_statement_stub_body, PassStatementStubBody};
|
||||
@@ -10,10 +11,10 @@ pub use unrecognized_platform::{
|
||||
unrecognized_platform, UnrecognizedPlatformCheck, UnrecognizedPlatformName,
|
||||
};
|
||||
|
||||
mod bad_version_info_comparison;
|
||||
mod docstring_in_stubs;
|
||||
mod non_empty_stub_body;
|
||||
mod pass_statement_stub_body;
|
||||
mod prefix_type_params;
|
||||
mod unrecognized_platform;
|
||||
|
||||
mod simple_defaults;
|
||||
mod unrecognized_platform;
|
||||
|
||||
@@ -22,21 +22,25 @@ define_violation!(
|
||||
/// ## Example
|
||||
/// ```python
|
||||
/// if sys.platform.startswith("linux"):
|
||||
/// # Linux specific definitions
|
||||
/// # Linux specific definitions
|
||||
/// ...
|
||||
/// else:
|
||||
/// # Posix specific definitions
|
||||
/// # Posix specific definitions
|
||||
/// ...
|
||||
/// ```
|
||||
///
|
||||
/// Instead, use a simple string comparison, such as `==` or `!=`:
|
||||
/// ```python
|
||||
/// if sys.platform == "linux":
|
||||
/// # Linux specific definitions
|
||||
/// ...
|
||||
/// else:
|
||||
/// # Posix specific definitions
|
||||
/// ...
|
||||
/// ```
|
||||
///
|
||||
/// ## References
|
||||
/// * [PEP 484](https://peps.python.org/pep-0484/#version-and-platform-checking)
|
||||
/// - [PEP 484](https://peps.python.org/pep-0484/#version-and-platform-checking)
|
||||
pub struct UnrecognizedPlatformCheck;
|
||||
);
|
||||
impl Violation for UnrecognizedPlatformCheck {
|
||||
@@ -68,11 +72,11 @@ define_violation!(
|
||||
/// Use instead:
|
||||
/// ```python
|
||||
/// if sys.platform == "linux":
|
||||
/// ...
|
||||
/// ...
|
||||
/// ```
|
||||
///
|
||||
/// ## References
|
||||
/// * [PEP 484](https://peps.python.org/pep-0484/#version-and-platform-checking)
|
||||
/// - [PEP 484](https://peps.python.org/pep-0484/#version-and-platform-checking)
|
||||
pub struct UnrecognizedPlatformName {
|
||||
pub platform: String,
|
||||
}
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
source: crates/ruff/src/rules/flake8_pyi/mod.rs
|
||||
expression: diagnostics
|
||||
---
|
||||
[]
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
---
|
||||
source: crates/ruff/src/rules/flake8_pyi/mod.rs
|
||||
expression: diagnostics
|
||||
---
|
||||
- kind:
|
||||
BadVersionInfoComparison: ~
|
||||
location:
|
||||
row: 8
|
||||
column: 3
|
||||
end_location:
|
||||
row: 8
|
||||
column: 29
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
BadVersionInfoComparison: ~
|
||||
location:
|
||||
row: 10
|
||||
column: 3
|
||||
end_location:
|
||||
row: 10
|
||||
column: 29
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
BadVersionInfoComparison: ~
|
||||
location:
|
||||
row: 12
|
||||
column: 3
|
||||
end_location:
|
||||
row: 12
|
||||
column: 30
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
BadVersionInfoComparison: ~
|
||||
location:
|
||||
row: 14
|
||||
column: 3
|
||||
end_location:
|
||||
row: 14
|
||||
column: 30
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
BadVersionInfoComparison: ~
|
||||
location:
|
||||
row: 16
|
||||
column: 3
|
||||
end_location:
|
||||
row: 16
|
||||
column: 29
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
BadVersionInfoComparison: ~
|
||||
location:
|
||||
row: 18
|
||||
column: 3
|
||||
end_location:
|
||||
row: 18
|
||||
column: 27
|
||||
fix: ~
|
||||
parent: ~
|
||||
|
||||
@@ -39,6 +39,7 @@ define_violation!(
|
||||
/// def test_foo():
|
||||
/// assert something and something_else
|
||||
///
|
||||
///
|
||||
/// def test_bar():
|
||||
/// assert not (something or something_else)
|
||||
/// ```
|
||||
@@ -49,6 +50,7 @@ define_violation!(
|
||||
/// assert something
|
||||
/// assert something_else
|
||||
///
|
||||
///
|
||||
/// def test_bar():
|
||||
/// assert not something
|
||||
/// assert not something_else
|
||||
|
||||
@@ -48,11 +48,11 @@ pub struct Options {
|
||||
/// Expected type for multiple argument names in `@pytest.mark.parametrize`.
|
||||
/// The following values are supported:
|
||||
///
|
||||
/// * `csv` — a comma-separated list, e.g.
|
||||
/// - `csv` — a comma-separated list, e.g.
|
||||
/// `@pytest.mark.parametrize('name1,name2', ...)`
|
||||
/// * `tuple` (default) — e.g. `@pytest.mark.parametrize(('name1', 'name2'),
|
||||
/// ...)`
|
||||
/// * `list` — e.g. `@pytest.mark.parametrize(['name1', 'name2'], ...)`
|
||||
/// - `tuple` (default) — e.g.
|
||||
/// `@pytest.mark.parametrize(('name1', 'name2'), ...)`
|
||||
/// - `list` — e.g. `@pytest.mark.parametrize(['name1', 'name2'], ...)`
|
||||
pub parametrize_names_type: Option<types::ParametrizeNameType>,
|
||||
#[option(
|
||||
default = "list",
|
||||
@@ -62,8 +62,8 @@ pub struct Options {
|
||||
/// Expected type for the list of values rows in `@pytest.mark.parametrize`.
|
||||
/// The following values are supported:
|
||||
///
|
||||
/// * `tuple` — e.g. `@pytest.mark.parametrize('name', (1, 2, 3))`
|
||||
/// * `list` (default) — e.g. `@pytest.mark.parametrize('name', [1, 2, 3])`
|
||||
/// - `tuple` — e.g. `@pytest.mark.parametrize('name', (1, 2, 3))`
|
||||
/// - `list` (default) — e.g. `@pytest.mark.parametrize('name', [1, 2, 3])`
|
||||
pub parametrize_values_type: Option<types::ParametrizeValuesType>,
|
||||
#[option(
|
||||
default = "tuple",
|
||||
@@ -73,10 +73,10 @@ pub struct Options {
|
||||
/// Expected type for each row of values in `@pytest.mark.parametrize` in
|
||||
/// case of multiple parameters. The following values are supported:
|
||||
///
|
||||
/// * `tuple` (default) — e.g. `@pytest.mark.parametrize(('name1', 'name2'),
|
||||
/// [(1, 2), (3, 4)])`
|
||||
/// * `list` — e.g. `@pytest.mark.parametrize(('name1', 'name2'), [[1, 2],
|
||||
/// [3, 4]])`
|
||||
/// - `tuple` (default) — e.g.
|
||||
/// `@pytest.mark.parametrize(('name1', 'name2'), [(1, 2), (3, 4)])`
|
||||
/// - `list` — e.g.
|
||||
/// `@pytest.mark.parametrize(('name1', 'name2'), [[1, 2], [3, 4]])`
|
||||
pub parametrize_values_row_type: Option<types::ParametrizeValuesRowType>,
|
||||
#[option(
|
||||
default = r#"["BaseException", "Exception", "ValueError", "OSError", "IOError", "EnvironmentError", "socket.error"]"#,
|
||||
|
||||
@@ -22,7 +22,7 @@ define_violation!(
|
||||
/// strings, but be consistent.
|
||||
///
|
||||
/// ## Options
|
||||
/// * `flake8-quotes.inline-quotes`
|
||||
/// - `flake8-quotes.inline-quotes`
|
||||
///
|
||||
/// ## Example
|
||||
/// ```python
|
||||
@@ -67,7 +67,7 @@ define_violation!(
|
||||
/// strings, but be consistent.
|
||||
///
|
||||
/// ## Options
|
||||
/// * `flake8-quotes.multiline-quotes`
|
||||
/// - `flake8-quotes.multiline-quotes`
|
||||
///
|
||||
/// ## Example
|
||||
/// ```python
|
||||
@@ -115,7 +115,7 @@ define_violation!(
|
||||
/// strings, but be consistent.
|
||||
///
|
||||
/// ## Options
|
||||
/// * `flake8-quotes.docstring-quotes`
|
||||
/// - `flake8-quotes.docstring-quotes`
|
||||
///
|
||||
/// ## Example
|
||||
/// ```python
|
||||
|
||||
@@ -23,7 +23,7 @@ define_violation!(
|
||||
/// behavior. Instead, use the class's public interface.
|
||||
///
|
||||
/// ## Options
|
||||
/// * `flake8-self.ignore-names`
|
||||
/// - `flake8-self.ignore-names`
|
||||
///
|
||||
/// ## Example
|
||||
/// ```python
|
||||
@@ -31,6 +31,7 @@ define_violation!(
|
||||
/// def __init__(self):
|
||||
/// self._private_member = "..."
|
||||
///
|
||||
///
|
||||
/// var = Class()
|
||||
/// print(var._private_member)
|
||||
/// ```
|
||||
@@ -41,12 +42,13 @@ define_violation!(
|
||||
/// def __init__(self):
|
||||
/// self.public_member = "..."
|
||||
///
|
||||
///
|
||||
/// var = Class()
|
||||
/// print(var.public_member)
|
||||
/// ```
|
||||
///
|
||||
/// ## References
|
||||
/// * [_What is the meaning of single or double underscores before an object name?_](https://stackoverflow.com/questions/1301346/what-is-the-meaning-of-single-and-double-underscore-before-an-object-name)
|
||||
/// - [_What is the meaning of single or double underscores before an object name?_](https://stackoverflow.com/questions/1301346/what-is-the-meaning-of-single-and-double-underscore-before-an-object-name)
|
||||
pub struct PrivateMemberAccess {
|
||||
pub access: String,
|
||||
}
|
||||
|
||||
@@ -38,8 +38,7 @@ define_violation!(
|
||||
/// ```
|
||||
///
|
||||
/// ## References
|
||||
/// * [Python: "isinstance"](https://docs.python.org/3/library/functions.html#isinstance)
|
||||
/// ```
|
||||
/// - [Python: "isinstance"](https://docs.python.org/3/library/functions.html#isinstance)
|
||||
pub struct DuplicateIsinstanceCall {
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
@@ -76,20 +76,20 @@ impl Violation for NeedlessBool {
|
||||
}
|
||||
|
||||
define_violation!(
|
||||
/// ### What it does
|
||||
/// ## What it does
|
||||
/// Checks for three or more consecutive if-statements with direct returns
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
/// ## Why is this bad?
|
||||
/// These can be simplified by using a dictionary
|
||||
///
|
||||
/// ### Example
|
||||
/// ## Example
|
||||
/// ```python
|
||||
/// if x == 1:
|
||||
/// return "Hello"
|
||||
/// elif x == 2:
|
||||
/// return "Goodbye"
|
||||
/// else:
|
||||
/// return "Goodnight"
|
||||
/// return "Goodnight"
|
||||
/// ```
|
||||
///
|
||||
/// Use instead:
|
||||
@@ -129,14 +129,14 @@ impl Violation for UseTernaryOperator {
|
||||
}
|
||||
|
||||
define_violation!(
|
||||
/// ### What it does
|
||||
/// ## What it does
|
||||
/// Checks for `if` branches with identical arm bodies.
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
/// ## Why is this bad?
|
||||
/// If multiple arms of an `if` statement have the same body, using `or`
|
||||
/// better signals the intent of the statement.
|
||||
///
|
||||
/// ### Example
|
||||
/// ## Example
|
||||
/// ```python
|
||||
/// if x == 1:
|
||||
/// print("Hello")
|
||||
@@ -592,6 +592,7 @@ pub fn manual_dict_lookup(
|
||||
test: &Expr,
|
||||
body: &[Stmt],
|
||||
orelse: &[Stmt],
|
||||
parent: Option<&Stmt>,
|
||||
) {
|
||||
// Throughout this rule:
|
||||
// * Each if-statement's test must consist of a constant equality check with the same variable.
|
||||
@@ -633,6 +634,36 @@ pub fn manual_dict_lookup(
|
||||
return;
|
||||
}
|
||||
|
||||
// It's part of a bigger if-elif block:
|
||||
// https://github.com/MartinThoma/flake8-simplify/issues/115
|
||||
if let Some(StmtKind::If {
|
||||
orelse: parent_orelse,
|
||||
..
|
||||
}) = parent.map(|parent| &parent.node)
|
||||
{
|
||||
if parent_orelse.len() == 1 && stmt == &parent_orelse[0] {
|
||||
// TODO(charlie): These two cases have the same AST:
|
||||
//
|
||||
// if True:
|
||||
// pass
|
||||
// elif a:
|
||||
// b = 1
|
||||
// else:
|
||||
// b = 2
|
||||
//
|
||||
// if True:
|
||||
// pass
|
||||
// else:
|
||||
// if a:
|
||||
// b = 1
|
||||
// else:
|
||||
// b = 2
|
||||
//
|
||||
// We want to flag the latter, but not the former. Right now, we flag neither.
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let mut constants: FxHashSet<ComparableConstant> = FxHashSet::default();
|
||||
constants.insert(constant.into());
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ define_violation!(
|
||||
/// ```
|
||||
///
|
||||
/// ## References
|
||||
/// * [Python: "The with statement"](https://docs.python.org/3/reference/compound_stmts.html#the-with-statement)
|
||||
/// - [Python: "The with statement"](https://docs.python.org/3/reference/compound_stmts.html#the-with-statement)
|
||||
pub struct MultipleWithStatements {
|
||||
pub fixable: bool,
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
use ruff_macros::{define_violation, derive_message_formats};
|
||||
use rustpython_parser::ast::{Excepthandler, ExcepthandlerKind, Located, Stmt, StmtKind};
|
||||
|
||||
use ruff_macros::{define_violation, derive_message_formats};
|
||||
|
||||
use crate::ast::helpers;
|
||||
use crate::ast::helpers::compose_call_path;
|
||||
use crate::ast::types::Range;
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::registry::Diagnostic;
|
||||
@@ -52,9 +54,9 @@ pub fn use_contextlib_suppress(
|
||||
let ExcepthandlerKind::ExceptHandler { body, .. } = &handler.node;
|
||||
if body.len() == 1 {
|
||||
if matches!(body[0].node, StmtKind::Pass) {
|
||||
let handler_names: Vec<_> = helpers::extract_handler_names(handlers)
|
||||
let handler_names: Vec<String> = helpers::extract_handled_exceptions(handlers)
|
||||
.into_iter()
|
||||
.map(|call_path| helpers::format_call_path(&call_path))
|
||||
.filter_map(compose_call_path)
|
||||
.collect();
|
||||
let exception = if handler_names.is_empty() {
|
||||
"Exception".to_string()
|
||||
|
||||
@@ -160,8 +160,8 @@ pub fn yoda_conditions(
|
||||
if checker.patch(diagnostic.kind.rule()) {
|
||||
diagnostic.amend(Fix::replacement(
|
||||
suggestion,
|
||||
left.location,
|
||||
right.end_location.unwrap(),
|
||||
expr.location,
|
||||
expr.end_location.unwrap(),
|
||||
));
|
||||
}
|
||||
checker.diagnostics.push(diagnostic);
|
||||
|
||||
@@ -62,4 +62,14 @@ expression: diagnostics
|
||||
column: 23
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
ManualDictLookup: ~
|
||||
location:
|
||||
row: 79
|
||||
column: 0
|
||||
end_location:
|
||||
row: 86
|
||||
column: 15
|
||||
fix: ~
|
||||
parent: ~
|
||||
|
||||
|
||||
@@ -216,6 +216,24 @@ expression: diagnostics
|
||||
column: 0
|
||||
end_location:
|
||||
row: 13
|
||||
column: 17
|
||||
column: 18
|
||||
parent: ~
|
||||
- kind:
|
||||
YodaConditions:
|
||||
suggestion: (60 * 60) < SomeClass().settings.SOME_CONSTANT_VALUE
|
||||
location:
|
||||
row: 14
|
||||
column: 0
|
||||
end_location:
|
||||
row: 14
|
||||
column: 52
|
||||
fix:
|
||||
content: (60 * 60) < SomeClass().settings.SOME_CONSTANT_VALUE
|
||||
location:
|
||||
row: 14
|
||||
column: 0
|
||||
end_location:
|
||||
row: 14
|
||||
column: 52
|
||||
parent: ~
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ define_violation!(
|
||||
/// automatic way.
|
||||
///
|
||||
/// ## Options
|
||||
/// * `flake8-tidy-imports.banned-api`
|
||||
/// - `flake8-tidy-imports.banned-api`
|
||||
pub struct BannedApi {
|
||||
pub name: String,
|
||||
pub message: String,
|
||||
|
||||
@@ -47,7 +47,7 @@ define_violation!(
|
||||
/// > ```
|
||||
///
|
||||
/// ## Options
|
||||
/// * `flake8-tidy-imports.ban-relative-imports`
|
||||
/// - `flake8-tidy-imports.ban-relative-imports`
|
||||
///
|
||||
/// ## Example
|
||||
/// ```python
|
||||
|
||||
@@ -22,8 +22,9 @@ define_violation!(
|
||||
///
|
||||
/// ## Why is this bad?
|
||||
/// In some projects, certain imports are required to be present in all
|
||||
/// files. For example, some projects assume that `from __future__
|
||||
/// import annotations` is enabled, and thus require that import to be
|
||||
/// files. For example, some projects assume that
|
||||
/// `from __future__ import annotations` is enabled,
|
||||
/// and thus require that import to be
|
||||
/// present in all files. Omitting a "required" import (as specified by
|
||||
/// the user) can cause errors or unexpected behavior.
|
||||
///
|
||||
|
||||
@@ -180,8 +180,8 @@ pub struct Options {
|
||||
///
|
||||
/// The default ("furthest-to-closest") is equivalent to isort's
|
||||
/// `reverse-relative` default (`reverse-relative = false`); setting
|
||||
/// this to "closest-to-furthest" is equivalent to isort's `reverse-relative
|
||||
/// = true`.
|
||||
/// this to "closest-to-furthest" is equivalent to isort's
|
||||
/// `reverse-relative = true`.
|
||||
pub relative_imports_order: Option<RelativeImportsOrder>,
|
||||
#[option(
|
||||
default = r#"[]"#,
|
||||
|
||||
@@ -20,7 +20,7 @@ define_violation!(
|
||||
/// Functions with a high complexity are hard to understand and maintain.
|
||||
///
|
||||
/// ## Options
|
||||
/// * `mccabe.max-complexity`
|
||||
/// - `mccabe.max-complexity`
|
||||
///
|
||||
/// ## Example
|
||||
/// ```python
|
||||
|
||||
@@ -41,8 +41,8 @@ mod tests {
|
||||
&indexer,
|
||||
&directives,
|
||||
&settings,
|
||||
flags::Autofix::Enabled,
|
||||
flags::Noqa::Enabled,
|
||||
flags::Autofix::Enabled,
|
||||
);
|
||||
let actual = diagnostics
|
||||
.iter()
|
||||
|
||||
@@ -31,7 +31,7 @@ define_violation!(
|
||||
/// ```
|
||||
///
|
||||
/// ## References
|
||||
/// * [_Why You Should Probably Never Use pandas inplace=True_](https://towardsdatascience.com/why-you-should-probably-never-use-pandas-inplace-true-9f9f211849e4)
|
||||
/// - [_Why You Should Probably Never Use pandas inplace=True_](https://towardsdatascience.com/why-you-should-probably-never-use-pandas-inplace-true-9f9f211849e4)
|
||||
pub struct UseOfInplaceArgument;
|
||||
);
|
||||
impl AlwaysAutofixableViolation for UseOfInplaceArgument {
|
||||
|
||||
@@ -17,7 +17,7 @@ define_violation!(
|
||||
///
|
||||
/// > ..."magic" objects or attributes that live in user-controlled
|
||||
/// > namespaces. E.g. `__init__`, `__import__` or `__file__`. Never invent
|
||||
/// such names; only use them as documented.
|
||||
/// > such names; only use them as documented.
|
||||
///
|
||||
/// ## Example
|
||||
/// ```python
|
||||
|
||||
@@ -16,16 +16,16 @@ define_violation!(
|
||||
/// [PEP 8] recommends the use of `cls` as the first argument for all class
|
||||
/// methods:
|
||||
///
|
||||
/// > Always use cls for the first argument to class methods.
|
||||
/// > Always use `cls` for the first argument to class methods.
|
||||
/// >
|
||||
/// > If a function argument’s name clashes with a reserved keyword, it is generally better to
|
||||
/// > append a single trailing underscore rather than use an abbreviation or spelling corruption.
|
||||
/// > Thus class_ is better than clss. (Perhaps better is to avoid such clashes by using a synonym.)
|
||||
/// > Thus `class_` is better than `clss`. (Perhaps better is to avoid such clashes by using a synonym.)
|
||||
///
|
||||
/// ## Options
|
||||
/// * `pep8-naming.classmethod-decorators`
|
||||
/// * `pep8-naming.staticmethod-decorators`
|
||||
/// * `pep8-naming.ignore-names`
|
||||
/// - `pep8-naming.classmethod-decorators`
|
||||
/// - `pep8-naming.staticmethod-decorators`
|
||||
/// - `pep8-naming.ignore-names`
|
||||
///
|
||||
/// ## Example
|
||||
/// ```python
|
||||
|
||||
@@ -20,12 +20,12 @@ define_violation!(
|
||||
/// >
|
||||
/// > If a function argument’s name clashes with a reserved keyword, it is generally better to
|
||||
/// > append a single trailing underscore rather than use an abbreviation or spelling corruption.
|
||||
/// > Thus class_ is better than clss. (Perhaps better is to avoid such clashes by using a synonym.)
|
||||
/// > Thus `class_` is better than `clss`. (Perhaps better is to avoid such clashes by using a synonym.)
|
||||
///
|
||||
/// ## Options
|
||||
/// * `pep8-naming.classmethod-decorators`
|
||||
/// * `pep8-naming.staticmethod-decorators`
|
||||
/// * `pep8-naming.ignore-names`
|
||||
/// - `pep8-naming.classmethod-decorators`
|
||||
/// - `pep8-naming.staticmethod-decorators`
|
||||
/// - `pep8-naming.ignore-names`
|
||||
///
|
||||
/// ## Example
|
||||
/// ```python
|
||||
|
||||
@@ -19,7 +19,7 @@ define_violation!(
|
||||
/// > prevailing style (e.g. threading.py), to retain backwards compatibility.
|
||||
///
|
||||
/// ## Options
|
||||
/// * `pep8-naming.ignore-names`
|
||||
/// - `pep8-naming.ignore-names`
|
||||
///
|
||||
/// ## Example
|
||||
/// ```python
|
||||
|
||||
@@ -25,8 +25,8 @@ define_violation!(
|
||||
/// > a leading underscore (e.g. `_socket`).
|
||||
///
|
||||
/// ## Example
|
||||
/// * Instead of `example-module-name` or `example module name`, use `example_module_name`.
|
||||
/// * Instead of `ExampleModule`, use `example_module`.
|
||||
/// - Instead of `example-module-name` or `example module name`, use `example_module_name`.
|
||||
/// - Instead of `ExampleModule`, use `example_module`.
|
||||
///
|
||||
/// [PEP 8]: https://peps.python.org/pep-0008/#package-and-module-names
|
||||
pub struct InvalidModuleName {
|
||||
|
||||
@@ -17,10 +17,10 @@ define_violation!(
|
||||
/// > Function names should be lowercase, with words separated by underscores as necessary to
|
||||
/// > improve readability. Variable names follow the same convention as function names. mixedCase
|
||||
/// > is allowed only in contexts where that's already the prevailing style (e.g. threading.py),
|
||||
/// to retain backwards compatibility.
|
||||
/// > to retain backwards compatibility.
|
||||
///
|
||||
/// ## Options
|
||||
/// * `pep8-naming.ignore-names`
|
||||
/// - `pep8-naming.ignore-names`
|
||||
///
|
||||
/// ## Example
|
||||
/// ```python
|
||||
|
||||
@@ -61,40 +61,40 @@ pub fn is_overlong(
|
||||
pub fn is_keyword_token(token: &Tok) -> bool {
|
||||
matches!(
|
||||
token,
|
||||
Tok::False { .. }
|
||||
| Tok::True { .. }
|
||||
| Tok::None { .. }
|
||||
| Tok::And { .. }
|
||||
| Tok::As { .. }
|
||||
| Tok::Assert { .. }
|
||||
| Tok::Await { .. }
|
||||
| Tok::Break { .. }
|
||||
| Tok::Class { .. }
|
||||
| Tok::Continue { .. }
|
||||
| Tok::Def { .. }
|
||||
| Tok::Del { .. }
|
||||
| Tok::Elif { .. }
|
||||
| Tok::Else { .. }
|
||||
| Tok::Except { .. }
|
||||
| Tok::Finally { .. }
|
||||
| Tok::For { .. }
|
||||
| Tok::From { .. }
|
||||
| Tok::Global { .. }
|
||||
| Tok::If { .. }
|
||||
| Tok::Import { .. }
|
||||
| Tok::In { .. }
|
||||
| Tok::Is { .. }
|
||||
| Tok::Lambda { .. }
|
||||
| Tok::Nonlocal { .. }
|
||||
| Tok::Not { .. }
|
||||
| Tok::Or { .. }
|
||||
| Tok::Pass { .. }
|
||||
| Tok::Raise { .. }
|
||||
| Tok::Return { .. }
|
||||
| Tok::Try { .. }
|
||||
| Tok::While { .. }
|
||||
| Tok::With { .. }
|
||||
| Tok::Yield { .. }
|
||||
Tok::False
|
||||
| Tok::True
|
||||
| Tok::None
|
||||
| Tok::And
|
||||
| Tok::As
|
||||
| Tok::Assert
|
||||
| Tok::Await
|
||||
| Tok::Break
|
||||
| Tok::Class
|
||||
| Tok::Continue
|
||||
| Tok::Def
|
||||
| Tok::Del
|
||||
| Tok::Elif
|
||||
| Tok::Else
|
||||
| Tok::Except
|
||||
| Tok::Finally
|
||||
| Tok::For
|
||||
| Tok::From
|
||||
| Tok::Global
|
||||
| Tok::If
|
||||
| Tok::Import
|
||||
| Tok::In
|
||||
| Tok::Is
|
||||
| Tok::Lambda
|
||||
| Tok::Nonlocal
|
||||
| Tok::Not
|
||||
| Tok::Or
|
||||
| Tok::Pass
|
||||
| Tok::Raise
|
||||
| Tok::Return
|
||||
| Tok::Try
|
||||
| Tok::While
|
||||
| Tok::With
|
||||
| Tok::Yield
|
||||
)
|
||||
}
|
||||
|
||||
@@ -104,3 +104,55 @@ pub fn is_singleton_token(token: &Tok) -> bool {
|
||||
Tok::False { .. } | Tok::True { .. } | Tok::None { .. },
|
||||
)
|
||||
}
|
||||
|
||||
pub fn is_op_token(token: &Tok) -> bool {
|
||||
matches!(
|
||||
token,
|
||||
Tok::Lpar
|
||||
| Tok::Rpar
|
||||
| Tok::Lsqb
|
||||
| Tok::Rsqb
|
||||
| Tok::Comma
|
||||
| Tok::Semi
|
||||
| Tok::Plus
|
||||
| Tok::Minus
|
||||
| Tok::Star
|
||||
| Tok::Slash
|
||||
| Tok::Vbar
|
||||
| Tok::Amper
|
||||
| Tok::Less
|
||||
| Tok::Greater
|
||||
| Tok::Equal
|
||||
| Tok::Dot
|
||||
| Tok::Percent
|
||||
| Tok::Lbrace
|
||||
| Tok::Rbrace
|
||||
| Tok::NotEqual
|
||||
| Tok::LessEqual
|
||||
| Tok::GreaterEqual
|
||||
| Tok::Tilde
|
||||
| Tok::CircumFlex
|
||||
| Tok::LeftShift
|
||||
| Tok::RightShift
|
||||
| Tok::DoubleStar
|
||||
| Tok::PlusEqual
|
||||
| Tok::MinusEqual
|
||||
| Tok::StarEqual
|
||||
| Tok::SlashEqual
|
||||
| Tok::PercentEqual
|
||||
| Tok::AmperEqual
|
||||
| Tok::VbarEqual
|
||||
| Tok::CircumflexEqual
|
||||
| Tok::LeftShiftEqual
|
||||
| Tok::RightShiftEqual
|
||||
| Tok::DoubleStarEqual
|
||||
| Tok::DoubleSlash
|
||||
| Tok::DoubleSlashEqual
|
||||
| Tok::At
|
||||
| Tok::AtEqual
|
||||
| Tok::Rarrow
|
||||
| Tok::Ellipsis
|
||||
| Tok::ColonEqual
|
||||
| Tok::Colon
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3,6 +3,8 @@ use rustpython_parser::ast::Location;
|
||||
use rustpython_parser::lexer::LexResult;
|
||||
use rustpython_parser::Tok;
|
||||
|
||||
use crate::rules::pycodestyle::helpers::{is_keyword_token, is_op_token};
|
||||
|
||||
use crate::ast::types::Range;
|
||||
use crate::source_code::Locator;
|
||||
|
||||
@@ -62,36 +64,7 @@ fn build_line<'a>(
|
||||
continue;
|
||||
}
|
||||
|
||||
if matches!(
|
||||
tok,
|
||||
Tok::Amper
|
||||
| Tok::AmperEqual
|
||||
| Tok::CircumFlex
|
||||
| Tok::CircumflexEqual
|
||||
| Tok::Colon
|
||||
| Tok::ColonEqual
|
||||
| Tok::DoubleSlash
|
||||
| Tok::DoubleSlashEqual
|
||||
| Tok::DoubleStar
|
||||
| Tok::Equal
|
||||
| Tok::Greater
|
||||
| Tok::GreaterEqual
|
||||
| Tok::Less
|
||||
| Tok::LessEqual
|
||||
| Tok::Minus
|
||||
| Tok::MinusEqual
|
||||
| Tok::NotEqual
|
||||
| Tok::Percent
|
||||
| Tok::PercentEqual
|
||||
| Tok::Plus
|
||||
| Tok::PlusEqual
|
||||
| Tok::Slash
|
||||
| Tok::SlashEqual
|
||||
| Tok::Star
|
||||
| Tok::StarEqual
|
||||
| Tok::Vbar
|
||||
| Tok::VbarEqual
|
||||
) {
|
||||
if is_op_token(tok) {
|
||||
flags.insert(TokenFlags::OPERATOR);
|
||||
}
|
||||
|
||||
@@ -106,44 +79,7 @@ fn build_line<'a>(
|
||||
flags.insert(TokenFlags::PUNCTUATION);
|
||||
}
|
||||
|
||||
if matches!(
|
||||
tok,
|
||||
Tok::False
|
||||
| Tok::None
|
||||
| Tok::True
|
||||
| Tok::And
|
||||
| Tok::As
|
||||
| Tok::Assert
|
||||
| Tok::Async
|
||||
| Tok::Await
|
||||
| Tok::Break
|
||||
| Tok::Class
|
||||
| Tok::Continue
|
||||
| Tok::Def
|
||||
| Tok::Del
|
||||
| Tok::Elif
|
||||
| Tok::Else
|
||||
| Tok::Except
|
||||
| Tok::Finally
|
||||
| Tok::For
|
||||
| Tok::From
|
||||
| Tok::Global
|
||||
| Tok::If
|
||||
| Tok::Import
|
||||
| Tok::In
|
||||
| Tok::Is
|
||||
| Tok::Lambda
|
||||
| Tok::Nonlocal
|
||||
| Tok::Not
|
||||
| Tok::Or
|
||||
| Tok::Pass
|
||||
| Tok::Raise
|
||||
| Tok::Return
|
||||
| Tok::Try
|
||||
| Tok::While
|
||||
| Tok::With
|
||||
| Tok::Yield
|
||||
) {
|
||||
if is_keyword_token(tok) {
|
||||
flags.insert(TokenFlags::KEYWORD);
|
||||
}
|
||||
|
||||
|
||||
@@ -42,6 +42,7 @@ mod tests {
|
||||
#[test_case(Rule::NotInTest, Path::new("E713.py"))]
|
||||
#[test_case(Rule::NotIsTest, Path::new("E714.py"))]
|
||||
#[test_case(Rule::SyntaxError, Path::new("E999.py"))]
|
||||
#[test_case(Rule::IndentationContainsTabs, Path::new("W19.py"))]
|
||||
#[test_case(Rule::TrailingWhitespace, Path::new("W29.py"))]
|
||||
#[test_case(Rule::TrueFalseComparison, Path::new("E712.py"))]
|
||||
#[test_case(Rule::TypeComparison, Path::new("E721.py"))]
|
||||
@@ -100,6 +101,11 @@ mod tests {
|
||||
#[test_case(Rule::WhitespaceAfterOpenBracket, Path::new("E20.py"))]
|
||||
#[test_case(Rule::WhitespaceBeforeCloseBracket, Path::new("E20.py"))]
|
||||
#[test_case(Rule::WhitespaceBeforePunctuation, Path::new("E20.py"))]
|
||||
#[test_case(
|
||||
Rule::UnexpectedSpacesAroundKeywordParameterEquals,
|
||||
Path::new("E25.py")
|
||||
)]
|
||||
#[test_case(Rule::MissingWhitespaceAroundParameterEquals, Path::new("E25.py"))]
|
||||
fn logical(rule_code: Rule, path: &Path) -> Result<()> {
|
||||
let snapshot = format!("{}_{}", rule_code.noqa_code(), path.to_string_lossy());
|
||||
let diagnostics = test_path(
|
||||
|
||||
@@ -19,7 +19,7 @@ define_violation!(
|
||||
/// ## Example
|
||||
/// ```python
|
||||
/// try:
|
||||
/// raise(KeyboardInterrupt("You probably don't mean to break CTRL-C."))
|
||||
/// raise KeyboardInterrupt("You probably don't mean to break CTRL-C.")
|
||||
/// except:
|
||||
/// print("But a bare `except` will ignore keyboard interrupts.")
|
||||
/// ```
|
||||
@@ -33,9 +33,9 @@ define_violation!(
|
||||
/// ```
|
||||
///
|
||||
/// ## References
|
||||
/// * [PEP 8](https://www.python.org/dev/peps/pep-0008/#programming-recommendations)
|
||||
/// * [Python: "Exception hierarchy"](https://docs.python.org/3/library/exceptions.html#exception-hierarchy)
|
||||
/// * [Google Python Style Guide: "Exceptions"](https://google.github.io/styleguide/pyguide.html#24-exceptions)
|
||||
/// - [PEP 8](https://www.python.org/dev/peps/pep-0008/#programming-recommendations)
|
||||
/// - [Python: "Exception hierarchy"](https://docs.python.org/3/library/exceptions.html#exception-hierarchy)
|
||||
/// - [Google Python Style Guide: "Exceptions"](https://google.github.io/styleguide/pyguide.html#24-exceptions)
|
||||
pub struct BareExcept;
|
||||
);
|
||||
impl Violation for BareExcept {
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
use ruff_macros::{define_violation, derive_message_formats};
|
||||
use rustpython_parser::ast::Location;
|
||||
|
||||
use crate::ast::types::Range;
|
||||
use crate::ast::whitespace::leading_space;
|
||||
use crate::registry::Diagnostic;
|
||||
use crate::violation::Violation;
|
||||
|
||||
define_violation!(
|
||||
pub struct IndentationContainsTabs;
|
||||
);
|
||||
impl Violation for IndentationContainsTabs {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!("Indentation contains tabs")
|
||||
}
|
||||
}
|
||||
|
||||
/// W191
|
||||
pub fn indentation_contains_tabs(lineno: usize, line: &str) -> Option<Diagnostic> {
|
||||
let indent = leading_space(line);
|
||||
|
||||
if indent.contains('\t') {
|
||||
Some(Diagnostic::new(
|
||||
IndentationContainsTabs,
|
||||
Range::new(
|
||||
Location::new(lineno + 1, 0),
|
||||
Location::new(lineno + 1, indent.chars().count()),
|
||||
),
|
||||
))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
@@ -21,6 +21,8 @@ pub use indentation::{
|
||||
NoIndentedBlock, NoIndentedBlockComment, OverIndented, UnexpectedIndentation,
|
||||
UnexpectedIndentationComment,
|
||||
};
|
||||
|
||||
pub use indentation_contains_tabs::{indentation_contains_tabs, IndentationContainsTabs};
|
||||
pub use invalid_escape_sequence::{invalid_escape_sequence, InvalidEscapeSequence};
|
||||
pub use lambda_assignment::{lambda_assignment, LambdaAssignment};
|
||||
pub use line_too_long::{line_too_long, LineTooLong};
|
||||
@@ -48,6 +50,11 @@ pub use whitespace_before_comment::{
|
||||
NoSpaceAfterInlineComment, TooFewSpacesBeforeInlineComment,
|
||||
};
|
||||
|
||||
pub use whitespace_around_named_parameter_equals::{
|
||||
whitespace_around_named_parameter_equals, MissingWhitespaceAroundParameterEquals,
|
||||
UnexpectedSpacesAroundKeywordParameterEquals,
|
||||
};
|
||||
|
||||
mod ambiguous_class_name;
|
||||
mod ambiguous_function_name;
|
||||
mod ambiguous_variable_name;
|
||||
@@ -58,6 +65,7 @@ mod errors;
|
||||
mod extraneous_whitespace;
|
||||
mod imports;
|
||||
mod indentation;
|
||||
mod indentation_contains_tabs;
|
||||
mod invalid_escape_sequence;
|
||||
mod lambda_assignment;
|
||||
mod line_too_long;
|
||||
@@ -70,4 +78,5 @@ mod space_around_operator;
|
||||
mod trailing_whitespace;
|
||||
mod type_comparison;
|
||||
mod whitespace_around_keywords;
|
||||
mod whitespace_around_named_parameter_equals;
|
||||
mod whitespace_before_comment;
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
#![allow(dead_code)]
|
||||
|
||||
use rustpython_parser::ast::Location;
|
||||
use rustpython_parser::Tok;
|
||||
|
||||
use once_cell::sync::Lazy;
|
||||
use regex::Regex;
|
||||
use ruff_macros::{define_violation, derive_message_formats};
|
||||
|
||||
#[cfg(feature = "logical_lines")]
|
||||
use crate::rules::pycodestyle::helpers::is_op_token;
|
||||
|
||||
use crate::registry::DiagnosticKind;
|
||||
use crate::violation::Violation;
|
||||
|
||||
define_violation!(
|
||||
pub struct UnexpectedSpacesAroundKeywordParameterEquals;
|
||||
);
|
||||
impl Violation for UnexpectedSpacesAroundKeywordParameterEquals {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!("Unexpected spaces around keyword / parameter equals")
|
||||
}
|
||||
}
|
||||
|
||||
define_violation!(
|
||||
pub struct MissingWhitespaceAroundParameterEquals;
|
||||
);
|
||||
impl Violation for MissingWhitespaceAroundParameterEquals {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!("Missing whitespace around parameter equals")
|
||||
}
|
||||
}
|
||||
|
||||
static STARTSWITH_DEF_REGEX: Lazy<Regex> =
|
||||
Lazy::new(|| Regex::new(r"^(async\s+def|def)\b").unwrap());
|
||||
|
||||
/// E251, E252
|
||||
#[cfg(feature = "logical_lines")]
|
||||
pub fn whitespace_around_named_parameter_equals(
|
||||
tokens: &[(Location, &Tok, Location)],
|
||||
line: &str,
|
||||
) -> Vec<(Location, DiagnosticKind)> {
|
||||
let mut diagnostics = vec![];
|
||||
let mut parens = 0;
|
||||
let mut require_space = false;
|
||||
let mut no_space = false;
|
||||
let mut annotated_func_arg = false;
|
||||
let mut prev_end: Option<&Location> = None;
|
||||
|
||||
let in_def = STARTSWITH_DEF_REGEX.is_match(line);
|
||||
|
||||
for (start, token, end) in tokens {
|
||||
if **token == Tok::NonLogicalNewline {
|
||||
continue;
|
||||
}
|
||||
if no_space {
|
||||
no_space = false;
|
||||
if Some(start) != prev_end {
|
||||
diagnostics.push((
|
||||
*(prev_end.unwrap()),
|
||||
UnexpectedSpacesAroundKeywordParameterEquals.into(),
|
||||
));
|
||||
}
|
||||
}
|
||||
if require_space {
|
||||
require_space = false;
|
||||
if Some(start) == prev_end {
|
||||
diagnostics.push((*start, MissingWhitespaceAroundParameterEquals.into()));
|
||||
}
|
||||
}
|
||||
if is_op_token(token) {
|
||||
if **token == Tok::Lpar || **token == Tok::Lsqb {
|
||||
parens += 1;
|
||||
} else if **token == Tok::Rpar || **token == Tok::Rsqb {
|
||||
parens -= 1;
|
||||
} else if in_def && **token == Tok::Colon && parens == 1 {
|
||||
annotated_func_arg = true;
|
||||
} else if parens == 1 && **token == Tok::Comma {
|
||||
annotated_func_arg = false;
|
||||
} else if parens > 0 && **token == Tok::Equal {
|
||||
if annotated_func_arg && parens == 1 {
|
||||
require_space = true;
|
||||
if Some(start) == prev_end {
|
||||
diagnostics.push((*start, MissingWhitespaceAroundParameterEquals.into()));
|
||||
}
|
||||
} else {
|
||||
no_space = true;
|
||||
if Some(start) != prev_end {
|
||||
diagnostics.push((
|
||||
*(prev_end.unwrap()),
|
||||
UnexpectedSpacesAroundKeywordParameterEquals.into(),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if parens < 1 {
|
||||
annotated_func_arg = false;
|
||||
}
|
||||
}
|
||||
prev_end = Some(end);
|
||||
}
|
||||
diagnostics
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "logical_lines"))]
|
||||
pub fn whitespace_around_named_parameter_equals(
|
||||
_tokens: &[(Location, &Tok, Location)],
|
||||
_line: &str,
|
||||
) -> Vec<(Location, DiagnosticKind)> {
|
||||
vec![]
|
||||
}
|
||||
@@ -27,8 +27,8 @@ pub struct Options {
|
||||
"#
|
||||
)]
|
||||
/// Whether line-length violations (`E501`) should be triggered for
|
||||
/// comments starting with `task-tags` (by default: ["TODO", "FIXME",
|
||||
/// and "XXX"]).
|
||||
/// comments starting with `task-tags` (by default: \["TODO", "FIXME",
|
||||
/// and "XXX"\]).
|
||||
pub ignore_overlong_task_comments: Option<bool>,
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
---
|
||||
source: crates/ruff/src/rules/pycodestyle/mod.rs
|
||||
expression: diagnostics
|
||||
---
|
||||
- kind:
|
||||
UnexpectedSpacesAroundKeywordParameterEquals: ~
|
||||
location:
|
||||
row: 2
|
||||
column: 11
|
||||
end_location:
|
||||
row: 2
|
||||
column: 11
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
UnexpectedSpacesAroundKeywordParameterEquals: ~
|
||||
location:
|
||||
row: 2
|
||||
column: 13
|
||||
end_location:
|
||||
row: 2
|
||||
column: 13
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
UnexpectedSpacesAroundKeywordParameterEquals: ~
|
||||
location:
|
||||
row: 6
|
||||
column: 8
|
||||
end_location:
|
||||
row: 6
|
||||
column: 8
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
UnexpectedSpacesAroundKeywordParameterEquals: ~
|
||||
location:
|
||||
row: 8
|
||||
column: 7
|
||||
end_location:
|
||||
row: 8
|
||||
column: 7
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
UnexpectedSpacesAroundKeywordParameterEquals: ~
|
||||
location:
|
||||
row: 10
|
||||
column: 7
|
||||
end_location:
|
||||
row: 10
|
||||
column: 7
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
UnexpectedSpacesAroundKeywordParameterEquals: ~
|
||||
location:
|
||||
row: 10
|
||||
column: 9
|
||||
end_location:
|
||||
row: 10
|
||||
column: 9
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
UnexpectedSpacesAroundKeywordParameterEquals: ~
|
||||
location:
|
||||
row: 12
|
||||
column: 13
|
||||
end_location:
|
||||
row: 12
|
||||
column: 13
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
UnexpectedSpacesAroundKeywordParameterEquals: ~
|
||||
location:
|
||||
row: 15
|
||||
column: 28
|
||||
end_location:
|
||||
row: 15
|
||||
column: 28
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
UnexpectedSpacesAroundKeywordParameterEquals: ~
|
||||
location:
|
||||
row: 18
|
||||
column: 44
|
||||
end_location:
|
||||
row: 18
|
||||
column: 44
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
UnexpectedSpacesAroundKeywordParameterEquals: ~
|
||||
location:
|
||||
row: 23
|
||||
column: 7
|
||||
end_location:
|
||||
row: 23
|
||||
column: 7
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
UnexpectedSpacesAroundKeywordParameterEquals: ~
|
||||
location:
|
||||
row: 23
|
||||
column: 9
|
||||
end_location:
|
||||
row: 23
|
||||
column: 9
|
||||
fix: ~
|
||||
parent: ~
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
---
|
||||
source: crates/ruff/src/rules/pycodestyle/mod.rs
|
||||
expression: diagnostics
|
||||
---
|
||||
- kind:
|
||||
MissingWhitespaceAroundParameterEquals: ~
|
||||
location:
|
||||
row: 46
|
||||
column: 14
|
||||
end_location:
|
||||
row: 46
|
||||
column: 14
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
MissingWhitespaceAroundParameterEquals: ~
|
||||
location:
|
||||
row: 46
|
||||
column: 15
|
||||
end_location:
|
||||
row: 46
|
||||
column: 15
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
MissingWhitespaceAroundParameterEquals: ~
|
||||
location:
|
||||
row: 46
|
||||
column: 26
|
||||
end_location:
|
||||
row: 46
|
||||
column: 26
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
MissingWhitespaceAroundParameterEquals: ~
|
||||
location:
|
||||
row: 46
|
||||
column: 35
|
||||
end_location:
|
||||
row: 46
|
||||
column: 35
|
||||
fix: ~
|
||||
parent: ~
|
||||
|
||||
@@ -0,0 +1,385 @@
|
||||
---
|
||||
source: crates/ruff/src/rules/pycodestyle/mod.rs
|
||||
expression: diagnostics
|
||||
---
|
||||
- kind:
|
||||
IndentationContainsTabs: ~
|
||||
location:
|
||||
row: 3
|
||||
column: 0
|
||||
end_location:
|
||||
row: 3
|
||||
column: 1
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
IndentationContainsTabs: ~
|
||||
location:
|
||||
row: 9
|
||||
column: 0
|
||||
end_location:
|
||||
row: 9
|
||||
column: 1
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
IndentationContainsTabs: ~
|
||||
location:
|
||||
row: 16
|
||||
column: 0
|
||||
end_location:
|
||||
row: 16
|
||||
column: 1
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
IndentationContainsTabs: ~
|
||||
location:
|
||||
row: 21
|
||||
column: 0
|
||||
end_location:
|
||||
row: 21
|
||||
column: 1
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
IndentationContainsTabs: ~
|
||||
location:
|
||||
row: 26
|
||||
column: 0
|
||||
end_location:
|
||||
row: 26
|
||||
column: 1
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
IndentationContainsTabs: ~
|
||||
location:
|
||||
row: 32
|
||||
column: 0
|
||||
end_location:
|
||||
row: 32
|
||||
column: 1
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
IndentationContainsTabs: ~
|
||||
location:
|
||||
row: 38
|
||||
column: 0
|
||||
end_location:
|
||||
row: 38
|
||||
column: 1
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
IndentationContainsTabs: ~
|
||||
location:
|
||||
row: 44
|
||||
column: 0
|
||||
end_location:
|
||||
row: 44
|
||||
column: 1
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
IndentationContainsTabs: ~
|
||||
location:
|
||||
row: 45
|
||||
column: 0
|
||||
end_location:
|
||||
row: 45
|
||||
column: 9
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
IndentationContainsTabs: ~
|
||||
location:
|
||||
row: 54
|
||||
column: 0
|
||||
end_location:
|
||||
row: 54
|
||||
column: 1
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
IndentationContainsTabs: ~
|
||||
location:
|
||||
row: 58
|
||||
column: 0
|
||||
end_location:
|
||||
row: 58
|
||||
column: 1
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
IndentationContainsTabs: ~
|
||||
location:
|
||||
row: 61
|
||||
column: 0
|
||||
end_location:
|
||||
row: 61
|
||||
column: 1
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
IndentationContainsTabs: ~
|
||||
location:
|
||||
row: 62
|
||||
column: 0
|
||||
end_location:
|
||||
row: 62
|
||||
column: 5
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
IndentationContainsTabs: ~
|
||||
location:
|
||||
row: 63
|
||||
column: 0
|
||||
end_location:
|
||||
row: 63
|
||||
column: 5
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
IndentationContainsTabs: ~
|
||||
location:
|
||||
row: 64
|
||||
column: 0
|
||||
end_location:
|
||||
row: 64
|
||||
column: 5
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
IndentationContainsTabs: ~
|
||||
location:
|
||||
row: 65
|
||||
column: 0
|
||||
end_location:
|
||||
row: 65
|
||||
column: 5
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
IndentationContainsTabs: ~
|
||||
location:
|
||||
row: 66
|
||||
column: 0
|
||||
end_location:
|
||||
row: 66
|
||||
column: 1
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
IndentationContainsTabs: ~
|
||||
location:
|
||||
row: 73
|
||||
column: 0
|
||||
end_location:
|
||||
row: 73
|
||||
column: 1
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
IndentationContainsTabs: ~
|
||||
location:
|
||||
row: 78
|
||||
column: 0
|
||||
end_location:
|
||||
row: 78
|
||||
column: 1
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
IndentationContainsTabs: ~
|
||||
location:
|
||||
row: 83
|
||||
column: 0
|
||||
end_location:
|
||||
row: 83
|
||||
column: 1
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
IndentationContainsTabs: ~
|
||||
location:
|
||||
row: 88
|
||||
column: 0
|
||||
end_location:
|
||||
row: 88
|
||||
column: 1
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
IndentationContainsTabs: ~
|
||||
location:
|
||||
row: 91
|
||||
column: 0
|
||||
end_location:
|
||||
row: 91
|
||||
column: 1
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
IndentationContainsTabs: ~
|
||||
location:
|
||||
row: 92
|
||||
column: 0
|
||||
end_location:
|
||||
row: 92
|
||||
column: 5
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
IndentationContainsTabs: ~
|
||||
location:
|
||||
row: 98
|
||||
column: 0
|
||||
end_location:
|
||||
row: 98
|
||||
column: 1
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
IndentationContainsTabs: ~
|
||||
location:
|
||||
row: 99
|
||||
column: 0
|
||||
end_location:
|
||||
row: 99
|
||||
column: 8
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
IndentationContainsTabs: ~
|
||||
location:
|
||||
row: 102
|
||||
column: 0
|
||||
end_location:
|
||||
row: 102
|
||||
column: 1
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
IndentationContainsTabs: ~
|
||||
location:
|
||||
row: 105
|
||||
column: 0
|
||||
end_location:
|
||||
row: 105
|
||||
column: 1
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
IndentationContainsTabs: ~
|
||||
location:
|
||||
row: 110
|
||||
column: 0
|
||||
end_location:
|
||||
row: 110
|
||||
column: 1
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
IndentationContainsTabs: ~
|
||||
location:
|
||||
row: 125
|
||||
column: 0
|
||||
end_location:
|
||||
row: 125
|
||||
column: 1
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
IndentationContainsTabs: ~
|
||||
location:
|
||||
row: 131
|
||||
column: 0
|
||||
end_location:
|
||||
row: 131
|
||||
column: 1
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
IndentationContainsTabs: ~
|
||||
location:
|
||||
row: 132
|
||||
column: 0
|
||||
end_location:
|
||||
row: 132
|
||||
column: 2
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
IndentationContainsTabs: ~
|
||||
location:
|
||||
row: 133
|
||||
column: 0
|
||||
end_location:
|
||||
row: 133
|
||||
column: 2
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
IndentationContainsTabs: ~
|
||||
location:
|
||||
row: 136
|
||||
column: 0
|
||||
end_location:
|
||||
row: 136
|
||||
column: 1
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
IndentationContainsTabs: ~
|
||||
location:
|
||||
row: 137
|
||||
column: 0
|
||||
end_location:
|
||||
row: 137
|
||||
column: 1
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
IndentationContainsTabs: ~
|
||||
location:
|
||||
row: 138
|
||||
column: 0
|
||||
end_location:
|
||||
row: 138
|
||||
column: 2
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
IndentationContainsTabs: ~
|
||||
location:
|
||||
row: 139
|
||||
column: 0
|
||||
end_location:
|
||||
row: 139
|
||||
column: 2
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
IndentationContainsTabs: ~
|
||||
location:
|
||||
row: 140
|
||||
column: 0
|
||||
end_location:
|
||||
row: 140
|
||||
column: 1
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
IndentationContainsTabs: ~
|
||||
location:
|
||||
row: 143
|
||||
column: 0
|
||||
end_location:
|
||||
row: 143
|
||||
column: 1
|
||||
fix: ~
|
||||
parent: ~
|
||||
|
||||
@@ -5,6 +5,7 @@ use ruff_macros::{define_violation, derive_message_formats};
|
||||
use rustc_hash::FxHashSet;
|
||||
use rustpython_parser::ast::StmtKind;
|
||||
|
||||
use crate::ast::helpers::identifier_range;
|
||||
use crate::ast::types::Range;
|
||||
use crate::ast::whitespace::LinesWithTrailingNewline;
|
||||
use crate::ast::{cast, whitespace};
|
||||
@@ -837,7 +838,7 @@ fn missing_args(checker: &mut Checker, docstring: &Docstring, docstrings_args: &
|
||||
let names = missing_arg_names.into_iter().sorted().collect();
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
UndocumentedParam { names },
|
||||
Range::from_located(parent),
|
||||
identifier_range(parent, checker.locator),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,10 +8,10 @@ expression: diagnostics
|
||||
- y
|
||||
location:
|
||||
row: 283
|
||||
column: 4
|
||||
column: 8
|
||||
end_location:
|
||||
row: 293
|
||||
column: 16
|
||||
row: 283
|
||||
column: 11
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
@@ -20,10 +20,10 @@ expression: diagnostics
|
||||
- y
|
||||
location:
|
||||
row: 300
|
||||
column: 0
|
||||
column: 4
|
||||
end_location:
|
||||
row: 306
|
||||
column: 7
|
||||
row: 300
|
||||
column: 28
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
@@ -34,10 +34,10 @@ expression: diagnostics
|
||||
- z
|
||||
location:
|
||||
row: 324
|
||||
column: 4
|
||||
column: 8
|
||||
end_location:
|
||||
row: 330
|
||||
column: 11
|
||||
row: 324
|
||||
column: 25
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
@@ -48,10 +48,10 @@ expression: diagnostics
|
||||
- z
|
||||
location:
|
||||
row: 336
|
||||
column: 4
|
||||
column: 8
|
||||
end_location:
|
||||
row: 343
|
||||
column: 11
|
||||
row: 336
|
||||
column: 38
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
@@ -62,10 +62,10 @@ expression: diagnostics
|
||||
- z
|
||||
location:
|
||||
row: 349
|
||||
column: 4
|
||||
column: 8
|
||||
end_location:
|
||||
row: 355
|
||||
column: 11
|
||||
row: 349
|
||||
column: 39
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
@@ -75,10 +75,10 @@ expression: diagnostics
|
||||
- b
|
||||
location:
|
||||
row: 361
|
||||
column: 4
|
||||
column: 8
|
||||
end_location:
|
||||
row: 367
|
||||
column: 11
|
||||
row: 361
|
||||
column: 30
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
@@ -87,10 +87,10 @@ expression: diagnostics
|
||||
- y
|
||||
location:
|
||||
row: 389
|
||||
column: 0
|
||||
column: 4
|
||||
end_location:
|
||||
row: 398
|
||||
column: 7
|
||||
row: 389
|
||||
column: 27
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
@@ -101,10 +101,10 @@ expression: diagnostics
|
||||
- z
|
||||
location:
|
||||
row: 425
|
||||
column: 4
|
||||
column: 8
|
||||
end_location:
|
||||
row: 434
|
||||
column: 11
|
||||
row: 425
|
||||
column: 25
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
@@ -115,10 +115,10 @@ expression: diagnostics
|
||||
- z
|
||||
location:
|
||||
row: 440
|
||||
column: 4
|
||||
column: 8
|
||||
end_location:
|
||||
row: 453
|
||||
column: 11
|
||||
row: 440
|
||||
column: 38
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
@@ -128,10 +128,10 @@ expression: diagnostics
|
||||
- z
|
||||
location:
|
||||
row: 459
|
||||
column: 4
|
||||
column: 8
|
||||
end_location:
|
||||
row: 469
|
||||
column: 11
|
||||
row: 459
|
||||
column: 39
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
@@ -140,10 +140,10 @@ expression: diagnostics
|
||||
- y
|
||||
location:
|
||||
row: 489
|
||||
column: 4
|
||||
column: 8
|
||||
end_location:
|
||||
row: 497
|
||||
column: 11
|
||||
row: 489
|
||||
column: 29
|
||||
fix: ~
|
||||
parent: ~
|
||||
|
||||
|
||||
@@ -9,10 +9,10 @@ expression: diagnostics
|
||||
- z
|
||||
location:
|
||||
row: 1
|
||||
column: 0
|
||||
column: 4
|
||||
end_location:
|
||||
row: 11
|
||||
column: 12
|
||||
row: 1
|
||||
column: 5
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
@@ -22,10 +22,10 @@ expression: diagnostics
|
||||
- z
|
||||
location:
|
||||
row: 14
|
||||
column: 0
|
||||
column: 4
|
||||
end_location:
|
||||
row: 24
|
||||
column: 12
|
||||
row: 14
|
||||
column: 5
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
@@ -35,10 +35,10 @@ expression: diagnostics
|
||||
- z
|
||||
location:
|
||||
row: 27
|
||||
column: 0
|
||||
column: 4
|
||||
end_location:
|
||||
row: 36
|
||||
column: 12
|
||||
row: 27
|
||||
column: 5
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
@@ -48,10 +48,10 @@ expression: diagnostics
|
||||
- z
|
||||
location:
|
||||
row: 39
|
||||
column: 0
|
||||
column: 4
|
||||
end_location:
|
||||
row: 49
|
||||
column: 12
|
||||
row: 39
|
||||
column: 5
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
@@ -60,10 +60,10 @@ expression: diagnostics
|
||||
- y
|
||||
location:
|
||||
row: 52
|
||||
column: 0
|
||||
column: 4
|
||||
end_location:
|
||||
row: 62
|
||||
column: 12
|
||||
row: 52
|
||||
column: 5
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
@@ -72,10 +72,10 @@ expression: diagnostics
|
||||
- y
|
||||
location:
|
||||
row: 65
|
||||
column: 0
|
||||
column: 4
|
||||
end_location:
|
||||
row: 74
|
||||
column: 12
|
||||
row: 65
|
||||
column: 5
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
@@ -84,10 +84,10 @@ expression: diagnostics
|
||||
- y
|
||||
location:
|
||||
row: 77
|
||||
column: 0
|
||||
column: 4
|
||||
end_location:
|
||||
row: 84
|
||||
column: 12
|
||||
row: 77
|
||||
column: 5
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
@@ -96,10 +96,10 @@ expression: diagnostics
|
||||
- x
|
||||
location:
|
||||
row: 98
|
||||
column: 0
|
||||
column: 4
|
||||
end_location:
|
||||
row: 105
|
||||
column: 12
|
||||
row: 98
|
||||
column: 5
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
@@ -108,10 +108,10 @@ expression: diagnostics
|
||||
- "*args"
|
||||
location:
|
||||
row: 108
|
||||
column: 0
|
||||
column: 4
|
||||
end_location:
|
||||
row: 115
|
||||
column: 12
|
||||
row: 108
|
||||
column: 5
|
||||
fix: ~
|
||||
parent: ~
|
||||
|
||||
|
||||
@@ -9,10 +9,10 @@ expression: diagnostics
|
||||
- z
|
||||
location:
|
||||
row: 27
|
||||
column: 0
|
||||
column: 4
|
||||
end_location:
|
||||
row: 36
|
||||
column: 12
|
||||
row: 27
|
||||
column: 5
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
@@ -21,10 +21,10 @@ expression: diagnostics
|
||||
- y
|
||||
location:
|
||||
row: 65
|
||||
column: 0
|
||||
column: 4
|
||||
end_location:
|
||||
row: 74
|
||||
column: 12
|
||||
row: 65
|
||||
column: 5
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
@@ -33,10 +33,10 @@ expression: diagnostics
|
||||
- y
|
||||
location:
|
||||
row: 77
|
||||
column: 0
|
||||
column: 4
|
||||
end_location:
|
||||
row: 84
|
||||
column: 12
|
||||
row: 77
|
||||
column: 5
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
@@ -45,10 +45,10 @@ expression: diagnostics
|
||||
- x
|
||||
location:
|
||||
row: 98
|
||||
column: 0
|
||||
column: 4
|
||||
end_location:
|
||||
row: 105
|
||||
column: 12
|
||||
row: 98
|
||||
column: 5
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
@@ -57,10 +57,10 @@ expression: diagnostics
|
||||
- "*args"
|
||||
location:
|
||||
row: 108
|
||||
column: 0
|
||||
column: 4
|
||||
end_location:
|
||||
row: 115
|
||||
column: 12
|
||||
row: 108
|
||||
column: 5
|
||||
fix: ~
|
||||
parent: ~
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@ mod tests {
|
||||
#[test_case(Rule::UnusedImport, Path::new("F401_7.py"); "F401_7")]
|
||||
#[test_case(Rule::UnusedImport, Path::new("F401_8.py"); "F401_8")]
|
||||
#[test_case(Rule::UnusedImport, Path::new("F401_9.py"); "F401_9")]
|
||||
#[test_case(Rule::UnusedImport, Path::new("F401_10.py"); "F401_10")]
|
||||
#[test_case(Rule::ImportShadowedByLoopVar, Path::new("F402.py"); "F402")]
|
||||
#[test_case(Rule::ImportStar, Path::new("F403.py"); "F403")]
|
||||
#[test_case(Rule::LateFutureImport, Path::new("F404.py"); "F404")]
|
||||
@@ -262,8 +263,8 @@ mod tests {
|
||||
&indexer,
|
||||
&directives,
|
||||
&settings,
|
||||
flags::Autofix::Enabled,
|
||||
flags::Noqa::Enabled,
|
||||
flags::Autofix::Enabled,
|
||||
);
|
||||
diagnostics.sort_by_key(|diagnostic| diagnostic.location);
|
||||
let actual = diagnostics
|
||||
|
||||
@@ -33,7 +33,7 @@ define_violation!(
|
||||
/// ```
|
||||
///
|
||||
/// ## References
|
||||
/// * [PEP 498](https://www.python.org/dev/peps/pep-0498/)
|
||||
/// - [PEP 498](https://www.python.org/dev/peps/pep-0498/)
|
||||
pub struct FStringMissingPlaceholders;
|
||||
);
|
||||
impl AlwaysAutofixableViolation for FStringMissingPlaceholders {
|
||||
|
||||
@@ -26,7 +26,7 @@ define_violation!(
|
||||
/// [`dummy-variable-rgx`] pattern.
|
||||
///
|
||||
/// ## Options
|
||||
/// * `dummy-variable-rgx`
|
||||
/// - `dummy-variable-rgx`
|
||||
///
|
||||
/// ## Example
|
||||
/// ```python
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
source: crates/ruff/src/rules/pyflakes/mod.rs
|
||||
expression: diagnostics
|
||||
---
|
||||
[]
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user