Compare commits
2 Commits
main-backu
...
charlie/qu
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
603d3e1984 | ||
|
|
402b3c7f04 |
8
.github/workflows/benchmark.yaml
vendored
8
.github/workflows/benchmark.yaml
vendored
@@ -2,14 +2,6 @@ name: Benchmark
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- 'Cargo.toml'
|
||||
- 'Cargo.lock'
|
||||
- 'rust-toolchain'
|
||||
- 'crates/**'
|
||||
- '!crates/ruff_dev'
|
||||
- '!crates/ruff_shrinking'
|
||||
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
|
||||
60
.github/workflows/ci.yaml
vendored
60
.github/workflows/ci.yaml
vendored
@@ -19,39 +19,6 @@ env:
|
||||
PYTHON_VERSION: "3.11" # to build abi3 wheels
|
||||
|
||||
jobs:
|
||||
determine_changes:
|
||||
name: "Determine changes"
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
linter: ${{ steps.changed.outputs.linter_any_changed }}
|
||||
formatter: ${{ steps.changed.outputs.formatter_any_changed }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- uses: tj-actions/changed-files@v37
|
||||
id: changed
|
||||
with:
|
||||
files_yaml: |
|
||||
linter:
|
||||
- Cargo.toml
|
||||
- Cargo.lock
|
||||
- crates/**
|
||||
- "!crates/ruff_python_formatter/**"
|
||||
- "!crates/ruff_formatter/**"
|
||||
- "!crates/ruff_dev/**"
|
||||
- "!crates/ruff_shrinking/**"
|
||||
|
||||
formatter:
|
||||
- Cargo.toml
|
||||
- Cargo.lock
|
||||
- crates/ruff_python_formatter/**
|
||||
- crates/ruff_formatter/**
|
||||
- crates/ruff_python_trivia/**
|
||||
- crates/ruff_python_ast/**
|
||||
|
||||
|
||||
cargo-fmt:
|
||||
name: "cargo fmt"
|
||||
runs-on: ubuntu-latest
|
||||
@@ -86,12 +53,10 @@ jobs:
|
||||
- uses: actions/checkout@v3
|
||||
- name: "Install Rust toolchain"
|
||||
run: rustup show
|
||||
- name: "Install cargo insta"
|
||||
uses: taiki-e/install-action@v2
|
||||
with:
|
||||
tool: cargo-insta
|
||||
- run: pip install black[d]==23.1.0
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
# cargo insta 1.30.0 fails for some reason (https://github.com/mitsuhiko/insta/issues/392)
|
||||
- run: cargo install cargo-insta@=1.29.0
|
||||
- run: pip install black[d]==23.1.0
|
||||
- name: "Run tests (Ubuntu)"
|
||||
if: ${{ matrix.os == 'ubuntu-latest' }}
|
||||
run: cargo insta test --all --all-features --unreferenced reject
|
||||
@@ -170,11 +135,9 @@ jobs:
|
||||
ecosystem:
|
||||
name: "ecosystem"
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- cargo-test
|
||||
- determine_changes
|
||||
needs: cargo-test
|
||||
# Only runs on pull requests, since that is the only we way we can find the base version for comparison.
|
||||
if: github.event_name == 'pull_request' && needs.determine_changes.outputs.linter == 'true'
|
||||
if: github.event_name == 'pull_request'
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-python@v4
|
||||
@@ -319,23 +282,16 @@ jobs:
|
||||
if: ${{ env.MKDOCS_INSIDERS_SSH_KEY_EXISTS != 'true' }}
|
||||
run: mkdocs build --strict -f mkdocs.generated.yml
|
||||
|
||||
check-formatter-ecosystem:
|
||||
name: "Formatter ecosystem and progress checks"
|
||||
check-formatter-stability:
|
||||
name: "Check formatter stability"
|
||||
runs-on: ubuntu-latest
|
||||
needs: determine_changes
|
||||
if: needs.determine_changes.outputs.formatter == 'true'
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: "Install Rust toolchain"
|
||||
run: rustup show
|
||||
- name: "Cache rust"
|
||||
uses: Swatinem/rust-cache@v2
|
||||
- name: "Formatter progress"
|
||||
run: scripts/formatter_progress.sh
|
||||
- name: "Github step summary"
|
||||
run: grep "similarity index" target/progress_projects_report.txt | sort > $GITHUB_STEP_SUMMARY
|
||||
# CPython is not black formatted, so we run only the stability check
|
||||
- name: "Clone CPython 3.10"
|
||||
run: git clone --branch 3.10 --depth 1 https://github.com/python/cpython.git crates/ruff/resources/test/cpython
|
||||
- name: "Check CPython stability"
|
||||
- name: "Check stability"
|
||||
run: cargo run --bin ruff_dev -- format-dev --stability-check crates/ruff/resources/test/cpython
|
||||
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -10,7 +10,7 @@ schemastore
|
||||
# `maturin develop` and ecosystem_all_check.sh
|
||||
.venv*
|
||||
# Formatter debugging (crates/ruff_python_formatter/README.md)
|
||||
scratch.*
|
||||
scratch.py
|
||||
# Created by `perf` (CONTRIBUTING.md)
|
||||
perf.data
|
||||
perf.data.old
|
||||
|
||||
185
CONTRIBUTING.md
185
CONTRIBUTING.md
@@ -71,7 +71,7 @@ pipx install pre-commit # or `pip install pre-commit` if you have a virtualenv
|
||||
|
||||
### Development
|
||||
|
||||
After cloning the repository, run Ruff locally from the repository root with:
|
||||
After cloning the repository, run Ruff locally with:
|
||||
|
||||
```shell
|
||||
cargo run -p ruff_cli -- check /path/to/file.py --no-cache
|
||||
@@ -110,34 +110,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.
|
||||
If you're working on a rule, this is the crate for you.
|
||||
- `crates/ruff_benchmark`: binary crate for running micro-benchmarks.
|
||||
- `crates/ruff_cache`: library crate for caching lint results.
|
||||
- `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`), see the [`cargo dev`](#cargo-dev) section below.
|
||||
- `crates/ruff_diagnostics`: library crate for the rule-independent abstractions in the lint
|
||||
diagnostics APIs.
|
||||
- `crates/ruff_formatter`: library crate for language agnostic code formatting logic based on an
|
||||
intermediate representation. The backend for `ruff_python_formatter`.
|
||||
`cargo dev generate-all`).
|
||||
- `crates/ruff_diagnostics`: library crate for the lint diagnostics APIs.
|
||||
- `crates/ruff_formatter`: library crate for generic code formatting logic based on an intermediate
|
||||
representation.
|
||||
- `crates/ruff_index`: library crate inspired by `rustc_index`.
|
||||
- `crates/ruff_macros`: proc macro crate containing macros used by Ruff.
|
||||
- `crates/ruff_macros`: library crate containing macros used by Ruff.
|
||||
- `crates/ruff_python_ast`: library crate containing Python-specific AST types and utilities.
|
||||
- `crates/ruff_python_codegen`: library crate containing utilities for generating Python source code.
|
||||
- `crates/ruff_python_codegen`: library crate containing utilities for generating Python source code.
|
||||
- `crates/ruff_python_formatter`: library crate implementing the Python formatter. Emits an
|
||||
intermediate representation for each node, which `ruff_formatter` prints based on the configured
|
||||
line length.
|
||||
- `crates/ruff_python_formatter`: library crate containing Python-specific code formatting logic.
|
||||
- `crates/ruff_python_semantic`: library crate containing Python-specific semantic analysis logic,
|
||||
including Ruff's semantic model. Used to resolve queries like "What import does this variable
|
||||
refer to?"
|
||||
- `crates/ruff_python_stdlib`: library crate containing Python-specific standard library data, e.g.
|
||||
the names of all built-in exceptions and which standard library types are immutable.
|
||||
- `crates/ruff_python_trivia`: library crate containing Python-specific trivia utilities (e.g.,
|
||||
for analyzing indentation, newlines, etc.).
|
||||
- `crates/ruff_python_parser`: library crate containing the Python parser.
|
||||
- `crates/ruff_wasm`: library crate for exposing Ruff as a WebAssembly module. Powers the
|
||||
[Ruff Playground](https://play.ruff.rs/).
|
||||
including Ruff's semantic model.
|
||||
- `crates/ruff_python_stdlib`: library crate containing Python-specific standard library data.
|
||||
- `crates/ruff_python_whitespace`: library crate containing Python-specific whitespace analysis
|
||||
logic.
|
||||
- `crates/ruff_rustpython`: library crate containing `RustPython`-specific utilities.
|
||||
- `crates/ruff_testing_macros`: library crate containing macros used for testing Ruff.
|
||||
- `crates/ruff_textwrap`: library crate to indent and dedent Python source code.
|
||||
- `crates/ruff_wasm`: library crate for exposing Ruff as a WebAssembly module.
|
||||
|
||||
### Example: Adding a new lint rule
|
||||
|
||||
@@ -155,13 +148,10 @@ At a high level, the steps involved in adding a new lint rule are as follows:
|
||||
(e.g., `pub(crate) fn assert_false`) based on whatever inputs are required for the rule (e.g.,
|
||||
an `ast::StmtAssert` node).
|
||||
|
||||
1. Define the logic for invoking the diagnostic in `crates/ruff/src/checkers/ast/analyze` (for
|
||||
AST-based rules), `crates/ruff/src/checkers/tokens.rs` (for token-based rules),
|
||||
`crates/ruff/src/checkers/physical_lines.rs` (for text-based rules),
|
||||
`crates/ruff/src/checkers/filesystem.rs` (for filesystem-based rules), etc. For AST-based rules,
|
||||
you'll likely want to modify `analyze/statement.rs` (if your rule is based on analyzing
|
||||
statements, like imports) or `analyze/expression.rs` (if your rule is based on analyzing
|
||||
expressions, like function calls).
|
||||
1. Define the logic for triggering the violation in `crates/ruff/src/checkers/ast/mod.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).
|
||||
|
||||
1. Map the violation struct to a rule code in `crates/ruff/src/codes.rs` (e.g., `B011`).
|
||||
|
||||
@@ -223,12 +213,9 @@ Once you've completed the code for the rule itself, you can define tests with th
|
||||
For example, if you're adding a new rule named `E402`, you would run:
|
||||
|
||||
```shell
|
||||
cargo run -p ruff_cli -- check crates/ruff/resources/test/fixtures/pycodestyle/E402.py --no-cache --select E402
|
||||
cargo run -p ruff_cli -- check crates/ruff/resources/test/fixtures/pycodestyle/E402.py --no-cache
|
||||
```
|
||||
|
||||
**Note:** Only a subset of rules are enabled by default. When testing a new rule, ensure that
|
||||
you activate it by adding `--select ${rule_code}` to the command.
|
||||
|
||||
1. Add the test to the relevant `crates/ruff/src/rules/[linter]/mod.rs` file. If you're contributing
|
||||
a rule to a pre-existing set, you should be able to find a similar example to pattern-match
|
||||
against. If you're adding a new linter, you'll need to create a new `mod.rs` file (see,
|
||||
@@ -315,7 +302,7 @@ even patch releases may contain [non-backwards-compatible changes](https://semve
|
||||
1. Run the release workflow with the version number (without starting `v`) as input. Make sure
|
||||
main has your merged PR as last commit
|
||||
1. The release workflow will do the following:
|
||||
1. Build all the assets. If this fails (even though we tested in step 4), we haven't tagged or
|
||||
1. Build all the assets. If this fails (even though we tested in step 4), we haven’t tagged or
|
||||
uploaded anything, you can restart after pushing a fix.
|
||||
1. Upload to PyPI.
|
||||
1. Create and push the Git tag (as extracted from `pyproject.toml`). We create the Git tag only
|
||||
@@ -424,13 +411,6 @@ Summary
|
||||
159.43 ± 2.48 times faster than 'pycodestyle crates/ruff/resources/test/cpython'
|
||||
```
|
||||
|
||||
To benchmark a subset of rules, e.g. `LineTooLong` and `DocLineTooLong`:
|
||||
|
||||
```shell
|
||||
cargo build --release && hyperfine --warmup 10 \
|
||||
"./target/release/ruff ./crates/ruff/resources/test/cpython/ --no-cache -e --select W505,E501"
|
||||
```
|
||||
|
||||
You can run `poetry install` from `./scripts/benchmarks` to create a working environment for the
|
||||
above. All reported benchmarks were computed using the versions specified by
|
||||
`./scripts/benchmarks/pyproject.toml` on Python 3.11.
|
||||
@@ -728,9 +708,9 @@ diagnostics, then our current compilation pipeline proceeds as follows:
|
||||
|
||||
1. **File discovery**: Given paths like `foo/`, locate all Python files in any specified subdirectories, taking into account our hierarchical settings system and any `exclude` options.
|
||||
|
||||
1. **Package resolution**: Determine the "package root" for every file by traversing over its parent directories and looking for `__init__.py` files.
|
||||
1. **Package resolution**: Determine the “package root” for every file by traversing over its parent directories and looking for `__init__.py` files.
|
||||
|
||||
1. **Cache initialization**: For every "package root", initialize an empty cache.
|
||||
1. **Cache initialization**: For every “package root”, initialize an empty cache.
|
||||
|
||||
1. **Analysis**: For every file, in parallel:
|
||||
|
||||
@@ -738,7 +718,7 @@ diagnostics, then our current compilation pipeline proceeds as follows:
|
||||
|
||||
1. **Tokenization**: Run the lexer over the file to generate a token stream.
|
||||
|
||||
1. **Indexing**: Extract metadata from the token stream, such as: comment ranges, `# noqa` locations, `# isort: off` locations, "doc lines", etc.
|
||||
1. **Indexing**: Extract metadata from the token stream, such as: comment ranges, `# noqa` locations, `# isort: off` locations, “doc lines”, etc.
|
||||
|
||||
1. **Token-based rule evaluation**: Run any lint rules that are based on the contents of the token stream (e.g., commented-out code).
|
||||
|
||||
@@ -748,9 +728,9 @@ diagnostics, then our current compilation pipeline proceeds as follows:
|
||||
|
||||
1. **Parsing**: Run the parser over the token stream to produce an AST. (This consumes the token stream, so anything that relies on the token stream needs to happen before parsing.)
|
||||
|
||||
1. **AST-based rule evaluation**: Run any lint rules that are based on the AST. This includes the vast majority of lint rules. As part of this step, we also build the semantic model for the current file as we traverse over the AST. Some lint rules are evaluated eagerly, as we iterate over the AST, while others are evaluated in a deferred manner (e.g., unused imports, since we can't determine whether an import is unused until we've finished analyzing the entire file), after we've finished the initial traversal.
|
||||
1. **AST-based rule evaluation**: Run any lint rules that are based on the AST. This includes the vast majority of lint rules. As part of this step, we also build the semantic model for the current file as we traverse over the AST. Some lint rules are evaluated eagerly, as we iterate over the AST, while others are evaluated in a deferred manner (e.g., unused imports, since we can’t determine whether an import is unused until we’ve finished analyzing the entire file), after we’ve finished the initial traversal.
|
||||
|
||||
1. **Import-based rule evaluation**: Run any lint rules that are based on the module's imports (e.g., import sorting). These could, in theory, be included in the AST-based rule evaluation phase — they're just separated for simplicity.
|
||||
1. **Import-based rule evaluation**: Run any lint rules that are based on the module’s imports (e.g., import sorting). These could, in theory, be included in the AST-based rule evaluation phase — they’re just separated for simplicity.
|
||||
|
||||
1. **Physical line-based rule evaluation**: Run any lint rules that are based on physical lines (e.g., line-length).
|
||||
|
||||
@@ -759,116 +739,3 @@ diagnostics, then our current compilation pipeline proceeds as follows:
|
||||
1. **Cache write**: Write the generated diagnostics to the package cache using the file as a key.
|
||||
|
||||
1. **Reporting**: Print diagnostics in the specified format (text, JSON, etc.), to the specified output channel (stdout, a file, etc.).
|
||||
|
||||
### Import Categorization
|
||||
|
||||
To understand Ruff's import categorization system, we first need to define two concepts:
|
||||
|
||||
- "Project root": The directory containing the `pyproject.toml`, `ruff.toml`, or `.ruff.toml` file,
|
||||
discovered by identifying the "closest" such directory for each Python file. (If you're running
|
||||
via `ruff --config /path/to/pyproject.toml`, then the current working directory is used as the
|
||||
"project root".)
|
||||
- "Package root": The top-most directory defining the Python package that includes a given Python
|
||||
file. To find the package root for a given Python file, traverse up its parent directories until
|
||||
you reach a parent directory that doesn't contain an `__init__.py` file (and isn't marked as
|
||||
a [namespace package](https://beta.ruff.rs/docs/settings/#namespace-packages)); take the directory
|
||||
just before that, i.e., the first directory in the package.
|
||||
|
||||
For example, given:
|
||||
|
||||
```text
|
||||
my_project
|
||||
├── pyproject.toml
|
||||
└── src
|
||||
└── foo
|
||||
├── __init__.py
|
||||
└── bar
|
||||
├── __init__.py
|
||||
└── baz.py
|
||||
```
|
||||
|
||||
Then when analyzing `baz.py`, the project root would be the top-level directory (`./my_project`),
|
||||
and the package root would be `./my_project/src/foo`.
|
||||
|
||||
#### Project root
|
||||
|
||||
The project root does not have a significant impact beyond that all relative paths within the loaded
|
||||
configuration file are resolved relative to the project root.
|
||||
|
||||
For example, to indicate that `bar` above is a namespace package (it isn't, but let's run with it),
|
||||
the `pyproject.toml` would list `namespace-packages = ["./src/bar"]`, which would resolve
|
||||
to `my_project/src/bar`.
|
||||
|
||||
The same logic applies when providing a configuration file via `--config`. In that case, the
|
||||
_current working directory_ is used as the project root, and so all paths in that configuration file
|
||||
are resolved relative to the current working directory. (As a general rule, we want to avoid relying
|
||||
on the current working directory as much as possible, to ensure that Ruff exhibits the same behavior
|
||||
regardless of where and how you invoke it — but that's hard to avoid in this case.)
|
||||
|
||||
Additionally, if a `pyproject.toml` file _extends_ another configuration file, Ruff will still use
|
||||
the directory containing that `pyproject.toml` file as the project root. For example, if
|
||||
`./my_project/pyproject.toml` contains:
|
||||
|
||||
```toml
|
||||
[tool.ruff]
|
||||
extend = "/path/to/pyproject.toml"
|
||||
```
|
||||
|
||||
Then Ruff will use `./my_project` as the project root, even though the configuration file extends
|
||||
`/path/to/pyproject.toml`. As such, if the configuration file at `/path/to/pyproject.toml` contains
|
||||
any relative paths, they will be resolved relative to `./my_project`.
|
||||
|
||||
If a project uses nested configuration files, then Ruff would detect multiple project roots, one for
|
||||
each configuration file.
|
||||
|
||||
#### Package root
|
||||
|
||||
The package root is used to determine a file's "module path". Consider, again, `baz.py`. In that
|
||||
case, `./my_project/src/foo` was identified as the package root, so the module path for `baz.py`
|
||||
would resolve to `foo.bar.baz` — as computed by taking the relative path from the package root
|
||||
(inclusive of the root itself). The module path can be thought of as "the path you would use to
|
||||
import the module" (e.g., `import foo.bar.baz`).
|
||||
|
||||
The package root and module path are used to, e.g., convert relative to absolute imports, and for
|
||||
import categorization, as described below.
|
||||
|
||||
#### Import categorization
|
||||
|
||||
When sorting and formatting import blocks, Ruff categorizes every import into one of five
|
||||
categories:
|
||||
|
||||
1. **"Future"**: the import is a `__future__` import. That's easy: just look at the name of the
|
||||
imported module!
|
||||
1. **"Standard library"**: the import comes from the Python standard library (e.g., `import os`).
|
||||
This is easy too: we include a list of all known standard library modules in Ruff itself, so it's
|
||||
a simple lookup.
|
||||
1. **"Local folder"**: the import is a relative import (e.g., `from .foo import bar`). This is easy
|
||||
too: just check if the import includes a `level` (i.e., a dot-prefix).
|
||||
1. **"First party"**: the import is part of the current project. (More on this below.)
|
||||
1. **"Third party"**: everything else.
|
||||
|
||||
The real challenge lies in determining whether an import is first-party — everything else is either
|
||||
trivial, or (as in the case of third-party) merely defined as "not first-party".
|
||||
|
||||
There are three ways in which an import can be categorized as "first-party":
|
||||
|
||||
1. **Explicit settings**: the import is marked as such via the `known-first-party` setting. (This
|
||||
should generally be seen as an escape hatch.)
|
||||
1. **Same-package**: the imported module is in the same package as the current file. This gets back
|
||||
to the importance of the "package root" and the file's "module path". Imagine that we're
|
||||
analyzing `baz.py` above. If `baz.py` contains any imports that appear to come from the `foo`
|
||||
package (e.g., `from foo import bar` or `import foo.bar`), they'll be classified as first-party
|
||||
automatically. This check is as simple as comparing the first segment of the current file's
|
||||
module path to the first segment of the import.
|
||||
1. **Source roots**: Ruff supports a `[src](https://beta.ruff.rs/docs/settings/#src)` setting, which
|
||||
sets the directories to scan when identifying first-party imports. The algorithm is
|
||||
straightforward: given an import, like `import foo`, iterate over the directories enumerated in
|
||||
the `src` setting and, for each directory, check for the existence of a subdirectory `foo` or a
|
||||
file `foo.py`.
|
||||
|
||||
By default, `src` is set to the project root. In the above example, we'd want to set
|
||||
`src = ["./src"]` to ensure that we locate `./my_project/src/foo` and thus categorize `import foo`
|
||||
as first-party in `baz.py`. In practice, for this limited example, setting `src = ["./src"]` is
|
||||
unnecessary, as all imports within `./my_project/src/foo` would be categorized as first-party via
|
||||
the same-package heuristic; but your project contains multiple packages, you'll want to set `src`
|
||||
explicitly.
|
||||
|
||||
576
Cargo.lock
generated
576
Cargo.lock
generated
@@ -133,15 +133,6 @@ dependencies = [
|
||||
"os_str_bytes",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ascii-canvas"
|
||||
version = "3.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8824ecca2e851cec16968d54a01dd372ef8f95b244fb84b84e70128be347c3c6"
|
||||
dependencies = [
|
||||
"term",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "assert_cmd"
|
||||
version = "2.0.11"
|
||||
@@ -178,21 +169,6 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bit-set"
|
||||
version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1"
|
||||
dependencies = [
|
||||
"bit-vec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bit-vec"
|
||||
version = "0.6.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
@@ -212,7 +188,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6798148dccfbff0fae41c7574d2fa8f1ef3492fba0face179de5d8d447d67b05"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"regex-automata 0.3.0",
|
||||
"regex-automata",
|
||||
"serde",
|
||||
]
|
||||
|
||||
@@ -633,16 +609,6 @@ dependencies = [
|
||||
"dirs-sys 0.4.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs-next"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"dirs-sys-next",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs-sys"
|
||||
version = "0.3.7"
|
||||
@@ -666,17 +632,6 @@ dependencies = [
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs-sys-next"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"redox_users",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "doc-comment"
|
||||
version = "0.3.3"
|
||||
@@ -701,15 +656,6 @@ version = "1.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91"
|
||||
|
||||
[[package]]
|
||||
name = "ena"
|
||||
version = "0.14.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c533630cf40e9caa44bd91aadc88a75d75a4c3a12b4cfde353cbed41daa1e1f1"
|
||||
dependencies = [
|
||||
"log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "encode_unicode"
|
||||
version = "0.3.6"
|
||||
@@ -786,15 +732,9 @@ dependencies = [
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fixedbitset"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
|
||||
|
||||
[[package]]
|
||||
name = "flake8-to-ruff"
|
||||
version = "0.0.280"
|
||||
version = "0.0.278"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap",
|
||||
@@ -836,12 +776,6 @@ dependencies = [
|
||||
"percent-encoding",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fs-err"
|
||||
version = "2.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0845fa252299212f0389d64ba26f34fa32cfe41588355f21ed507c59a0f64541"
|
||||
|
||||
[[package]]
|
||||
name = "fsevent-sys"
|
||||
version = "4.1.0"
|
||||
@@ -1029,12 +963,6 @@ dependencies = [
|
||||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "indoc"
|
||||
version = "2.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2c785eefb63ebd0e33416dfcb8d6da0bf27ce752843a45632a67bf10d4d4b5c4"
|
||||
|
||||
[[package]]
|
||||
name = "inotify"
|
||||
version = "0.9.6"
|
||||
@@ -1057,15 +985,14 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "insta"
|
||||
version = "1.31.0"
|
||||
version = "1.30.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a0770b0a3d4c70567f0d58331f3088b0e4c4f56c9b8d764efe654b4a5d46de3a"
|
||||
checksum = "28491f7753051e5704d4d0ae7860d45fae3238d7d235bc4289dcd45c48d3cec3"
|
||||
dependencies = [
|
||||
"console",
|
||||
"globset",
|
||||
"lazy_static",
|
||||
"linked-hash-map",
|
||||
"regex",
|
||||
"similar",
|
||||
"walkdir",
|
||||
"yaml-rust",
|
||||
@@ -1159,28 +1086,6 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lalrpop"
|
||||
version = "0.20.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "da4081d44f4611b66c6dd725e6de3169f9f63905421e8626fcb86b6a898998b8"
|
||||
dependencies = [
|
||||
"ascii-canvas",
|
||||
"bit-set",
|
||||
"diff",
|
||||
"ena",
|
||||
"is-terminal",
|
||||
"itertools",
|
||||
"lalrpop-util",
|
||||
"petgraph",
|
||||
"regex",
|
||||
"regex-syntax 0.7.3",
|
||||
"string_cache",
|
||||
"term",
|
||||
"tiny-keccak",
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lalrpop-util"
|
||||
version = "0.20.0"
|
||||
@@ -1281,31 +1186,12 @@ version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09fc20d2ca12cb9f044c93e3bd6d32d523e6e2ec3db4f7b2939cd99026ecd3f0"
|
||||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
version = "0.4.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"scopeguard",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4"
|
||||
|
||||
[[package]]
|
||||
name = "matchers"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558"
|
||||
dependencies = [
|
||||
"regex-automata 0.1.10",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "matches"
|
||||
version = "0.1.10"
|
||||
@@ -1369,12 +1255,6 @@ version = "1.0.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "308d96db8debc727c3fd9744aac51751243420e46edf401010908da7f8d5e57c"
|
||||
|
||||
[[package]]
|
||||
name = "new_debug_unreachable"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54"
|
||||
|
||||
[[package]]
|
||||
name = "nextest-workspace-hack"
|
||||
version = "0.1.0"
|
||||
@@ -1393,6 +1273,12 @@ dependencies = [
|
||||
"static_assertions",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nohash-hasher"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451"
|
||||
|
||||
[[package]]
|
||||
name = "nom"
|
||||
version = "7.1.3"
|
||||
@@ -1421,16 +1307,6 @@ dependencies = [
|
||||
"windows-sys 0.45.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nu-ansi-term"
|
||||
version = "0.46.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84"
|
||||
dependencies = [
|
||||
"overload",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-bigint"
|
||||
version = "0.4.3"
|
||||
@@ -1513,35 +1389,6 @@ dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "overload"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39"
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
|
||||
dependencies = [
|
||||
"lock_api",
|
||||
"parking_lot_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot_core"
|
||||
version = "0.9.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"redox_syscall 0.3.5",
|
||||
"smallvec",
|
||||
"windows-targets 0.48.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "paste"
|
||||
version = "1.0.13"
|
||||
@@ -1633,23 +1480,14 @@ version = "2.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94"
|
||||
|
||||
[[package]]
|
||||
name = "petgraph"
|
||||
version = "0.6.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4dd7d28ee937e54fe3080c91faa1c3a46c06de6252988a7f4592ba2310ef22a4"
|
||||
dependencies = [
|
||||
"fixedbitset",
|
||||
"indexmap 1.9.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "phf"
|
||||
version = "0.11.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc"
|
||||
dependencies = [
|
||||
"phf_shared 0.11.2",
|
||||
"phf_macros",
|
||||
"phf_shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1659,7 +1497,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e8d39688d359e6b34654d328e262234662d16cc0f60ec8dcbe5e718709342a5a"
|
||||
dependencies = [
|
||||
"phf_generator",
|
||||
"phf_shared 0.11.2",
|
||||
"phf_shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1668,17 +1506,21 @@ version = "0.11.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0"
|
||||
dependencies = [
|
||||
"phf_shared 0.11.2",
|
||||
"phf_shared",
|
||||
"rand",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "phf_shared"
|
||||
version = "0.10.0"
|
||||
name = "phf_macros"
|
||||
version = "0.11.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096"
|
||||
checksum = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b"
|
||||
dependencies = [
|
||||
"siphasher",
|
||||
"phf_generator",
|
||||
"phf_shared",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.23",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1741,18 +1583,6 @@ version = "1.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "767eb9f07d4a5ebcb39bbf2d452058a93c011373abf6832e24194a1c3f004794"
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
|
||||
|
||||
[[package]]
|
||||
name = "precomputed-hash"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c"
|
||||
|
||||
[[package]]
|
||||
name = "predicates"
|
||||
version = "3.0.3"
|
||||
@@ -1877,18 +1707,6 @@ version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"rand_chacha",
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_chacha"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
|
||||
dependencies = [
|
||||
"ppv-lite86",
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
@@ -1897,9 +1715,6 @@ name = "rand_core"
|
||||
version = "0.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rayon"
|
||||
@@ -1960,17 +1775,8 @@ checksum = "89089e897c013b3deb627116ae56a6955a72b8bed395c9526af31c9fe528b484"
|
||||
dependencies = [
|
||||
"aho-corasick 1.0.2",
|
||||
"memchr",
|
||||
"regex-automata 0.3.0",
|
||||
"regex-syntax 0.7.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-automata"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132"
|
||||
dependencies = [
|
||||
"regex-syntax 0.6.29",
|
||||
"regex-automata",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1981,15 +1787,9 @@ checksum = "fa250384981ea14565685dea16a9ccc4d1c541a13f82b9c168572264d1df8c56"
|
||||
dependencies = [
|
||||
"aho-corasick 1.0.2",
|
||||
"memchr",
|
||||
"regex-syntax 0.7.3",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.6.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1"
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.7.3"
|
||||
@@ -2035,7 +1835,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ruff"
|
||||
version = "0.0.280"
|
||||
version = "0.0.278"
|
||||
dependencies = [
|
||||
"annotate-snippets 0.9.1",
|
||||
"anyhow",
|
||||
@@ -2056,12 +1856,14 @@ dependencies = [
|
||||
"log",
|
||||
"memchr",
|
||||
"natord",
|
||||
"nohash-hasher",
|
||||
"num-bigint",
|
||||
"num-traits",
|
||||
"once_cell",
|
||||
"path-absolutize",
|
||||
"pathdiff",
|
||||
"pep440_rs",
|
||||
"phf",
|
||||
"pretty_assertions",
|
||||
"pyproject-toml",
|
||||
"quick-junit",
|
||||
@@ -2072,16 +1874,15 @@ dependencies = [
|
||||
"ruff_index",
|
||||
"ruff_macros",
|
||||
"ruff_python_ast",
|
||||
"ruff_python_codegen",
|
||||
"ruff_python_index",
|
||||
"ruff_python_literal",
|
||||
"ruff_python_parser",
|
||||
"ruff_python_semantic",
|
||||
"ruff_python_stdlib",
|
||||
"ruff_python_trivia",
|
||||
"ruff_source_file",
|
||||
"ruff_python_whitespace",
|
||||
"ruff_rustpython",
|
||||
"ruff_text_size",
|
||||
"ruff_textwrap",
|
||||
"rustc-hash",
|
||||
"rustpython-format",
|
||||
"rustpython-parser",
|
||||
"schemars",
|
||||
"semver",
|
||||
"serde",
|
||||
@@ -2092,7 +1893,6 @@ dependencies = [
|
||||
"smallvec",
|
||||
"strum",
|
||||
"strum_macros",
|
||||
"tempfile",
|
||||
"test-case",
|
||||
"thiserror",
|
||||
"toml",
|
||||
@@ -2112,7 +1912,7 @@ dependencies = [
|
||||
"ruff",
|
||||
"ruff_python_ast",
|
||||
"ruff_python_formatter",
|
||||
"ruff_python_parser",
|
||||
"rustpython-parser",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tikv-jemallocator",
|
||||
@@ -2134,7 +1934,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ruff_cli"
|
||||
version = "0.0.280"
|
||||
version = "0.0.278"
|
||||
dependencies = [
|
||||
"annotate-snippets 0.9.1",
|
||||
"anyhow",
|
||||
@@ -2151,7 +1951,6 @@ dependencies = [
|
||||
"filetime",
|
||||
"glob",
|
||||
"ignore",
|
||||
"insta",
|
||||
"itertools",
|
||||
"itoa",
|
||||
"log",
|
||||
@@ -2163,20 +1962,17 @@ dependencies = [
|
||||
"ruff",
|
||||
"ruff_cache",
|
||||
"ruff_diagnostics",
|
||||
"ruff_macros",
|
||||
"ruff_python_ast",
|
||||
"ruff_python_formatter",
|
||||
"ruff_python_stdlib",
|
||||
"ruff_python_trivia",
|
||||
"ruff_source_file",
|
||||
"ruff_text_size",
|
||||
"ruff_textwrap",
|
||||
"rustc-hash",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"shellexpand",
|
||||
"similar",
|
||||
"strum",
|
||||
"tempfile",
|
||||
"tikv-jemallocator",
|
||||
"ureq",
|
||||
"walkdir",
|
||||
@@ -2191,7 +1987,6 @@ dependencies = [
|
||||
"clap",
|
||||
"ignore",
|
||||
"indicatif",
|
||||
"indoc",
|
||||
"itertools",
|
||||
"libcst",
|
||||
"log",
|
||||
@@ -2203,21 +1998,17 @@ dependencies = [
|
||||
"ruff_cli",
|
||||
"ruff_diagnostics",
|
||||
"ruff_formatter",
|
||||
"ruff_python_ast",
|
||||
"ruff_python_codegen",
|
||||
"ruff_python_formatter",
|
||||
"ruff_python_literal",
|
||||
"ruff_python_parser",
|
||||
"ruff_python_stdlib",
|
||||
"ruff_python_trivia",
|
||||
"ruff_textwrap",
|
||||
"rustpython-format",
|
||||
"rustpython-parser",
|
||||
"schemars",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"similar",
|
||||
"strum",
|
||||
"strum_macros",
|
||||
"tempfile",
|
||||
"toml",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2260,7 +2051,7 @@ dependencies = [
|
||||
"itertools",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"ruff_python_trivia",
|
||||
"ruff_textwrap",
|
||||
"syn 2.0.23",
|
||||
]
|
||||
|
||||
@@ -2268,33 +2059,26 @@ dependencies = [
|
||||
name = "ruff_python_ast"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bitflags 2.3.3",
|
||||
"insta",
|
||||
"is-macro",
|
||||
"itertools",
|
||||
"log",
|
||||
"memchr",
|
||||
"num-bigint",
|
||||
"num-traits",
|
||||
"once_cell",
|
||||
"ruff_python_parser",
|
||||
"ruff_python_trivia",
|
||||
"ruff_source_file",
|
||||
"ruff_python_whitespace",
|
||||
"ruff_text_size",
|
||||
"rustc-hash",
|
||||
"rustpython-ast",
|
||||
"rustpython-literal",
|
||||
"rustpython-parser",
|
||||
"serde",
|
||||
"smallvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ruff_python_codegen"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"ruff_python_ast",
|
||||
"ruff_python_literal",
|
||||
"ruff_python_parser",
|
||||
"ruff_source_file",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ruff_python_formatter"
|
||||
version = "0.0.0"
|
||||
@@ -2309,66 +2093,16 @@ dependencies = [
|
||||
"once_cell",
|
||||
"ruff_formatter",
|
||||
"ruff_python_ast",
|
||||
"ruff_python_index",
|
||||
"ruff_python_parser",
|
||||
"ruff_python_trivia",
|
||||
"ruff_source_file",
|
||||
"ruff_python_whitespace",
|
||||
"ruff_text_size",
|
||||
"rustc-hash",
|
||||
"rustpython-parser",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"similar",
|
||||
"smallvec",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ruff_python_index"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"itertools",
|
||||
"ruff_python_ast",
|
||||
"ruff_python_parser",
|
||||
"ruff_python_trivia",
|
||||
"ruff_source_file",
|
||||
"ruff_text_size",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ruff_python_literal"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"bitflags 2.3.3",
|
||||
"hexf-parse",
|
||||
"is-macro",
|
||||
"itertools",
|
||||
"lexical-parse-float",
|
||||
"num-bigint",
|
||||
"num-traits",
|
||||
"rand",
|
||||
"unic-ucd-category",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ruff_python_parser"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"insta",
|
||||
"is-macro",
|
||||
"itertools",
|
||||
"lalrpop",
|
||||
"lalrpop-util",
|
||||
"num-bigint",
|
||||
"num-traits",
|
||||
"ruff_python_ast",
|
||||
"ruff_text_size",
|
||||
"rustc-hash",
|
||||
"static_assertions",
|
||||
"tiny-keccak",
|
||||
"unic-emoji-char",
|
||||
"unic-ucd-ident",
|
||||
"unicode_names2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2387,13 +2121,14 @@ version = "0.0.0"
|
||||
dependencies = [
|
||||
"bitflags 2.3.3",
|
||||
"is-macro",
|
||||
"nohash-hasher",
|
||||
"num-traits",
|
||||
"ruff_index",
|
||||
"ruff_python_ast",
|
||||
"ruff_python_stdlib",
|
||||
"ruff_source_file",
|
||||
"ruff_text_size",
|
||||
"rustc-hash",
|
||||
"rustpython-parser",
|
||||
"smallvec",
|
||||
]
|
||||
|
||||
@@ -2402,54 +2137,36 @@ name = "ruff_python_stdlib"
|
||||
version = "0.0.0"
|
||||
|
||||
[[package]]
|
||||
name = "ruff_python_trivia"
|
||||
name = "ruff_python_whitespace"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"insta",
|
||||
"memchr",
|
||||
"ruff_python_ast",
|
||||
"ruff_python_parser",
|
||||
"ruff_source_file",
|
||||
"ruff_text_size",
|
||||
"smallvec",
|
||||
"unic-ucd-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ruff_shrinking"
|
||||
version = "0.1.0"
|
||||
name = "ruff_rustpython"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap",
|
||||
"fs-err",
|
||||
"regex",
|
||||
"ruff_python_ast",
|
||||
"ruff_python_parser",
|
||||
"ruff_text_size",
|
||||
"shlex",
|
||||
"tracing",
|
||||
"tracing-subscriber",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ruff_source_file"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"insta",
|
||||
"memchr",
|
||||
"once_cell",
|
||||
"ruff_text_size",
|
||||
"serde",
|
||||
"rustpython-parser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ruff_text_size"
|
||||
version = "0.0.0"
|
||||
source = "git+https://github.com/astral-sh/RustPython-Parser.git?rev=c174bbf1f29527edd43d432326327f16f47ab9e0#c174bbf1f29527edd43d432326327f16f47ab9e0"
|
||||
dependencies = [
|
||||
"schemars",
|
||||
"serde",
|
||||
"serde_test",
|
||||
"static_assertions",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ruff_textwrap"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"ruff_python_whitespace",
|
||||
"ruff_text_size",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2463,11 +2180,8 @@ dependencies = [
|
||||
"ruff",
|
||||
"ruff_diagnostics",
|
||||
"ruff_python_ast",
|
||||
"ruff_python_codegen",
|
||||
"ruff_python_formatter",
|
||||
"ruff_python_index",
|
||||
"ruff_python_parser",
|
||||
"ruff_source_file",
|
||||
"ruff_rustpython",
|
||||
"rustpython-parser",
|
||||
"serde",
|
||||
"serde-wasm-bindgen",
|
||||
"wasm-bindgen",
|
||||
@@ -2539,6 +2253,74 @@ dependencies = [
|
||||
"untrusted",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustpython-ast"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/astral-sh/RustPython-Parser.git?rev=c174bbf1f29527edd43d432326327f16f47ab9e0#c174bbf1f29527edd43d432326327f16f47ab9e0"
|
||||
dependencies = [
|
||||
"is-macro",
|
||||
"num-bigint",
|
||||
"rustpython-parser-core",
|
||||
"static_assertions",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustpython-format"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/astral-sh/RustPython-Parser.git?rev=c174bbf1f29527edd43d432326327f16f47ab9e0#c174bbf1f29527edd43d432326327f16f47ab9e0"
|
||||
dependencies = [
|
||||
"bitflags 2.3.3",
|
||||
"itertools",
|
||||
"num-bigint",
|
||||
"num-traits",
|
||||
"rustpython-literal",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustpython-literal"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/astral-sh/RustPython-Parser.git?rev=c174bbf1f29527edd43d432326327f16f47ab9e0#c174bbf1f29527edd43d432326327f16f47ab9e0"
|
||||
dependencies = [
|
||||
"hexf-parse",
|
||||
"is-macro",
|
||||
"lexical-parse-float",
|
||||
"num-traits",
|
||||
"unic-ucd-category",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustpython-parser"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/astral-sh/RustPython-Parser.git?rev=c174bbf1f29527edd43d432326327f16f47ab9e0#c174bbf1f29527edd43d432326327f16f47ab9e0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"is-macro",
|
||||
"itertools",
|
||||
"lalrpop-util",
|
||||
"log",
|
||||
"num-bigint",
|
||||
"num-traits",
|
||||
"phf",
|
||||
"phf_codegen",
|
||||
"rustc-hash",
|
||||
"rustpython-ast",
|
||||
"rustpython-parser-core",
|
||||
"tiny-keccak",
|
||||
"unic-emoji-char",
|
||||
"unic-ucd-ident",
|
||||
"unicode_names2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustpython-parser-core"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/astral-sh/RustPython-Parser.git?rev=c174bbf1f29527edd43d432326327f16f47ab9e0#c174bbf1f29527edd43d432326327f16f47ab9e0"
|
||||
dependencies = [
|
||||
"is-macro",
|
||||
"memchr",
|
||||
"ruff_text_size",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustversion"
|
||||
version = "1.0.13"
|
||||
@@ -2674,15 +2456,6 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_test"
|
||||
version = "1.0.176"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a2f49ace1498612d14f7e0b8245519584db8299541dfe31a06374a828d620ab"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_with"
|
||||
version = "3.0.0"
|
||||
@@ -2711,15 +2484,6 @@ dependencies = [
|
||||
"syn 2.0.23",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sharded-slab"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "shellexpand"
|
||||
version = "3.1.0"
|
||||
@@ -2729,12 +2493,6 @@ dependencies = [
|
||||
"dirs 5.0.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "shlex"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3"
|
||||
|
||||
[[package]]
|
||||
name = "similar"
|
||||
version = "2.2.1"
|
||||
@@ -2765,19 +2523,6 @@ version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
|
||||
|
||||
[[package]]
|
||||
name = "string_cache"
|
||||
version = "0.8.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f91138e76242f575eb1d3b38b4f1362f10d3a43f47d182a5b359af488a02293b"
|
||||
dependencies = [
|
||||
"new_debug_unreachable",
|
||||
"once_cell",
|
||||
"parking_lot",
|
||||
"phf_shared 0.10.0",
|
||||
"precomputed-hash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.10.0"
|
||||
@@ -2851,17 +2596,6 @@ dependencies = [
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "term"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f"
|
||||
dependencies = [
|
||||
"dirs-next",
|
||||
"rustversion",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "termcolor"
|
||||
version = "1.2.0"
|
||||
@@ -3112,36 +2846,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"valuable",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-log"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
"log",
|
||||
"tracing-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-subscriber"
|
||||
version = "0.3.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "30a651bc37f915e81f087d86e62a18eec5f79550c7faff886f7090b4ea757c77"
|
||||
dependencies = [
|
||||
"matchers",
|
||||
"nu-ansi-term",
|
||||
"once_cell",
|
||||
"regex",
|
||||
"sharded-slab",
|
||||
"smallvec",
|
||||
"thread_local",
|
||||
"tracing",
|
||||
"tracing-core",
|
||||
"tracing-log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3241,12 +2945,6 @@ version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c"
|
||||
|
||||
[[package]]
|
||||
name = "unicode_names2"
|
||||
version = "0.6.0"
|
||||
@@ -3301,12 +2999,6 @@ version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d023da39d1fde5a8a3fe1f3e01ca9632ada0a63e9797de55a879d6e2236277be"
|
||||
|
||||
[[package]]
|
||||
name = "valuable"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.4"
|
||||
|
||||
14
Cargo.toml
14
Cargo.toml
@@ -21,11 +21,12 @@ filetime = { version = "0.2.20" }
|
||||
glob = { version = "0.3.1" }
|
||||
globset = { version = "0.4.10" }
|
||||
ignore = { version = "0.4.20" }
|
||||
insta = { version = "1.31.0", feature = ["filters", "glob"] }
|
||||
insta = { version = "1.30.0" }
|
||||
is-macro = { version = "0.2.2" }
|
||||
itertools = { version = "0.10.5" }
|
||||
log = { version = "0.4.17" }
|
||||
memchr = "2.5.0"
|
||||
nohash-hasher = { version = "0.2.0" }
|
||||
num-bigint = { version = "0.4.3" }
|
||||
num-traits = { version = "0.2.15" }
|
||||
once_cell = { version = "1.17.1" }
|
||||
@@ -51,6 +52,15 @@ wsl = { version = "0.1.0" }
|
||||
# v1.0.1
|
||||
libcst = { git = "https://github.com/Instagram/LibCST.git", rev = "3cacca1a1029f05707e50703b49fe3dd860aa839", default-features = false }
|
||||
|
||||
# Please tag the RustPython version every time you update its revision here and in fuzz/Cargo.toml
|
||||
# Tagging the version ensures that older ruff versions continue to build from source even when we rebase our RustPython fork.
|
||||
# Current tag: v0.0.7
|
||||
ruff_text_size = { git = "https://github.com/astral-sh/RustPython-Parser.git", rev = "c174bbf1f29527edd43d432326327f16f47ab9e0" }
|
||||
rustpython-ast = { git = "https://github.com/astral-sh/RustPython-Parser.git", rev = "c174bbf1f29527edd43d432326327f16f47ab9e0" , default-features = false, features = ["num-bigint"]}
|
||||
rustpython-format = { git = "https://github.com/astral-sh/RustPython-Parser.git", rev = "c174bbf1f29527edd43d432326327f16f47ab9e0", default-features = false, features = ["num-bigint"] }
|
||||
rustpython-literal = { git = "https://github.com/astral-sh/RustPython-Parser.git", rev = "c174bbf1f29527edd43d432326327f16f47ab9e0", default-features = false }
|
||||
rustpython-parser = { git = "https://github.com/astral-sh/RustPython-Parser.git", rev = "c174bbf1f29527edd43d432326327f16f47ab9e0" , default-features = false, features = ["full-lexer", "num-bigint"] }
|
||||
|
||||
[profile.release]
|
||||
lto = "fat"
|
||||
codegen-units = 1
|
||||
@@ -63,7 +73,7 @@ opt-level = 3
|
||||
|
||||
# Reduce complexity of a parser function that would trigger a locals limit in a wasm tool.
|
||||
# https://github.com/bytecodealliance/wasm-tools/blob/b5c3d98e40590512a3b12470ef358d5c7b983b15/crates/wasmparser/src/limits.rs#L29
|
||||
[profile.dev.package.ruff_python_parser]
|
||||
[profile.dev.package.rustpython-parser]
|
||||
opt-level = 1
|
||||
|
||||
# Use the `--profile release-debug` flag to show symbols in release mode.
|
||||
|
||||
14
README.md
14
README.md
@@ -2,7 +2,7 @@
|
||||
|
||||
# Ruff
|
||||
|
||||
[](https://github.com/astral-sh/ruff)
|
||||
[](https://github.com/astral-sh/ruff)
|
||||
[](https://pypi.python.org/pypi/ruff)
|
||||
[](https://pypi.python.org/pypi/ruff)
|
||||
[](https://pypi.python.org/pypi/ruff)
|
||||
@@ -140,7 +140,7 @@ Ruff can also be used as a [pre-commit](https://pre-commit.com) hook:
|
||||
```yaml
|
||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||
# Ruff version.
|
||||
rev: v0.0.280
|
||||
rev: v0.0.278
|
||||
hooks:
|
||||
- id: ruff
|
||||
```
|
||||
@@ -397,7 +397,7 @@ Ruff is used by a number of major open-source projects and companies, including:
|
||||
- [PyTorch](https://github.com/pytorch/pytorch)
|
||||
- [Pydantic](https://github.com/pydantic/pydantic)
|
||||
- [Pylint](https://github.com/PyCQA/pylint)
|
||||
- [Reflex](https://github.com/reflex-dev/reflex)
|
||||
- [Pynecone](https://github.com/pynecone-io/pynecone)
|
||||
- [Robyn](https://github.com/sansyrox/robyn)
|
||||
- Scale AI ([Launch SDK](https://github.com/scaleapi/launch-python-client))
|
||||
- Snowflake ([SnowCLI](https://github.com/Snowflake-Labs/snowcli))
|
||||
@@ -424,13 +424,13 @@ Ruff is used by a number of major open-source projects and companies, including:
|
||||
If you're using Ruff, consider adding the Ruff badge to project's `README.md`:
|
||||
|
||||
```md
|
||||
[](https://github.com/astral-sh/ruff)
|
||||
[](https://github.com/astral-sh/ruff)
|
||||
```
|
||||
|
||||
...or `README.rst`:
|
||||
|
||||
```rst
|
||||
.. image:: https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json
|
||||
.. image:: https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/charliermarsh/ruff/main/assets/badge/v2.json
|
||||
:target: https://github.com/astral-sh/ruff
|
||||
:alt: Ruff
|
||||
```
|
||||
@@ -438,7 +438,7 @@ If you're using Ruff, consider adding the Ruff badge to project's `README.md`:
|
||||
...or, as HTML:
|
||||
|
||||
```html
|
||||
<a href="https://github.com/astral-sh/ruff"><img src="https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json" alt="Ruff" style="max-width:100%;"></a>
|
||||
<a href="https://github.com/astral-sh/ruff"><img src="https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/charliermarsh/ruff/main/assets/badge/v2.json" alt="Ruff" style="max-width:100%;"></a>
|
||||
```
|
||||
|
||||
## License
|
||||
@@ -447,6 +447,6 @@ MIT
|
||||
|
||||
<div align="center">
|
||||
<a target="_blank" href="https://astral.sh" style="background:none">
|
||||
<img src="https://raw.githubusercontent.com/astral-sh/ruff/main/assets/svg/Astral.svg">
|
||||
<img src="https://raw.githubusercontent.com/charliermarsh/ruff/main/assets/svg/Astral.svg">
|
||||
</a>
|
||||
</div>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "flake8-to-ruff"
|
||||
version = "0.0.280"
|
||||
version = "0.0.278"
|
||||
description = """
|
||||
Convert Flake8 configuration files to Ruff configuration files.
|
||||
"""
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "ruff"
|
||||
version = "0.0.280"
|
||||
version = "0.0.278"
|
||||
publish = false
|
||||
authors = { workspace = true }
|
||||
edition = { workspace = true }
|
||||
@@ -19,16 +19,13 @@ ruff_cache = { path = "../ruff_cache" }
|
||||
ruff_diagnostics = { path = "../ruff_diagnostics", features = ["serde"] }
|
||||
ruff_index = { path = "../ruff_index" }
|
||||
ruff_macros = { path = "../ruff_macros" }
|
||||
ruff_python_whitespace = { path = "../ruff_python_whitespace" }
|
||||
ruff_python_ast = { path = "../ruff_python_ast", features = ["serde"] }
|
||||
ruff_python_codegen = { path = "../ruff_python_codegen" }
|
||||
ruff_python_index = { path = "../ruff_python_index" }
|
||||
ruff_python_literal = { path = "../ruff_python_literal" }
|
||||
ruff_python_semantic = { path = "../ruff_python_semantic" }
|
||||
ruff_python_stdlib = { path = "../ruff_python_stdlib" }
|
||||
ruff_python_trivia = { path = "../ruff_python_trivia" }
|
||||
ruff_python_parser = { path = "../ruff_python_parser" }
|
||||
ruff_source_file = { path = "../ruff_source_file", features = ["serde"] }
|
||||
ruff_text_size = { path = "../ruff_text_size" }
|
||||
ruff_rustpython = { path = "../ruff_rustpython" }
|
||||
ruff_text_size = { workspace = true }
|
||||
ruff_textwrap = { path = "../ruff_textwrap" }
|
||||
|
||||
annotate-snippets = { version = "0.9.1", features = ["color"] }
|
||||
anyhow = { workspace = true }
|
||||
@@ -48,6 +45,7 @@ libcst = { workspace = true }
|
||||
log = { workspace = true }
|
||||
memchr = { workspace = true }
|
||||
natord = { version = "1.0.9" }
|
||||
nohash-hasher = { workspace = true }
|
||||
num-bigint = { workspace = true }
|
||||
num-traits = { workspace = true }
|
||||
once_cell = { workspace = true }
|
||||
@@ -57,13 +55,14 @@ path-absolutize = { workspace = true, features = [
|
||||
] }
|
||||
pathdiff = { version = "0.2.1" }
|
||||
pep440_rs = { version = "0.3.1", features = ["serde"] }
|
||||
phf = { version = "0.11", features = ["macros"] }
|
||||
pyproject-toml = { version = "0.6.0" }
|
||||
quick-junit = { version = "0.3.2" }
|
||||
regex = { workspace = true }
|
||||
result-like = { version = "0.4.6" }
|
||||
rustc-hash = { workspace = true }
|
||||
|
||||
|
||||
rustpython-format = { workspace = true }
|
||||
rustpython-parser = { workspace = true }
|
||||
schemars = { workspace = true, optional = true }
|
||||
semver = { version = "1.0.16" }
|
||||
serde = { workspace = true }
|
||||
@@ -87,7 +86,6 @@ pretty_assertions = "1.3.0"
|
||||
test-case = { workspace = true }
|
||||
# Disable colored output in tests
|
||||
colored = { workspace = true, features = ["no-color"] }
|
||||
tempfile = "3.6.0"
|
||||
|
||||
[features]
|
||||
default = []
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"""
|
||||
Should emit:
|
||||
B002 - on lines 18, 19, and 24
|
||||
B002 - on lines 15 and 20
|
||||
"""
|
||||
|
||||
|
||||
@@ -8,17 +8,13 @@ def this_is_all_fine(n):
|
||||
x = n + 1
|
||||
y = 1 + n
|
||||
z = +x + y
|
||||
a = n - 1
|
||||
b = 1 - n
|
||||
c = -a - b
|
||||
return +z, -c
|
||||
return +z
|
||||
|
||||
|
||||
def this_is_buggy(n):
|
||||
x = ++n
|
||||
y = --n
|
||||
return x, y
|
||||
return x
|
||||
|
||||
|
||||
def this_is_buggy_too(n):
|
||||
return ++n, --n
|
||||
return ++n
|
||||
|
||||
@@ -177,9 +177,6 @@ def str_okay(value=str("foo")):
|
||||
def bool_okay(value=bool("bar")):
|
||||
pass
|
||||
|
||||
# Allow immutable bytes() value
|
||||
def bytes_okay(value=bytes(1)):
|
||||
pass
|
||||
|
||||
# Allow immutable int() value
|
||||
def int_okay(value=int("12")):
|
||||
|
||||
@@ -97,10 +97,3 @@ def f():
|
||||
# variable name).
|
||||
for line_ in range(self.header_lines):
|
||||
fp.readline()
|
||||
|
||||
# Regression test: visitor didn't walk the elif test
|
||||
for key, value in current_crawler_tags.items():
|
||||
if key:
|
||||
pass
|
||||
elif wanted_tag_value != value:
|
||||
pass
|
||||
|
||||
@@ -17,37 +17,3 @@ from typing import TypedDict
|
||||
|
||||
class MyClass(TypedDict):
|
||||
id: int
|
||||
|
||||
|
||||
from threading import Event
|
||||
|
||||
|
||||
class CustomEvent(Event):
|
||||
def set(self) -> None:
|
||||
...
|
||||
|
||||
def str(self) -> None:
|
||||
...
|
||||
|
||||
|
||||
from logging import Filter, LogRecord
|
||||
|
||||
|
||||
class CustomFilter(Filter):
|
||||
def filter(self, record: LogRecord) -> bool:
|
||||
...
|
||||
|
||||
def str(self) -> None:
|
||||
...
|
||||
|
||||
|
||||
from typing_extensions import override
|
||||
|
||||
|
||||
class MyClass:
|
||||
@override
|
||||
def str(self):
|
||||
pass
|
||||
|
||||
def int(self):
|
||||
pass
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
|
||||
#!/usr/bin/env python
|
||||
@@ -50,12 +50,3 @@ _ = """a""" "b"
|
||||
_ = 'a' "b"
|
||||
|
||||
_ = rf"a" rf"b"
|
||||
|
||||
# Single-line explicit concatenation should be ignored.
|
||||
_ = "abc" + "def" + "ghi"
|
||||
_ = foo + "abc" + "def"
|
||||
_ = "abc" + foo + "def"
|
||||
_ = "abc" + "def" + foo
|
||||
_ = foo + bar + "abc"
|
||||
_ = "abc" + foo + bar
|
||||
_ = foo + "abc" + bar
|
||||
|
||||
@@ -1,10 +1,5 @@
|
||||
import logging
|
||||
from distutils import log
|
||||
|
||||
from logging_setup import logger
|
||||
|
||||
logging.warn("Hello World!")
|
||||
log.warn("Hello world!") # This shouldn't be considered as a logger candidate
|
||||
logger.warn("Hello world!")
|
||||
|
||||
logging . warn("Hello World!")
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
var: int
|
||||
a = var # OK
|
||||
|
||||
b = c = int # OK
|
||||
|
||||
a.b = int # OK
|
||||
|
||||
d, e = int, str # OK
|
||||
|
||||
f, g, h = int, str, TypeVar("T") # OK
|
||||
|
||||
i: TypeAlias = int | str # OK
|
||||
|
||||
j: TypeAlias = int # OK
|
||||
@@ -1,14 +0,0 @@
|
||||
var: int
|
||||
a = var # OK
|
||||
|
||||
b = c = int # PYI017
|
||||
|
||||
a.b = int # PYI017
|
||||
|
||||
d, e = int, str # PYI017
|
||||
|
||||
f, g, h = int, str, TypeVar("T") # PYI017
|
||||
|
||||
i: TypeAlias = int | str # OK
|
||||
|
||||
j: TypeAlias = int # OK
|
||||
@@ -1,12 +0,0 @@
|
||||
import typing
|
||||
from typing import TypeVar
|
||||
|
||||
_T = typing.TypeVar("_T")
|
||||
_P = TypeVar("_P")
|
||||
|
||||
# OK
|
||||
_UsedTypeVar = TypeVar("_UsedTypeVar")
|
||||
def func(arg: _UsedTypeVar) -> _UsedTypeVar: ...
|
||||
|
||||
_A, _B = TypeVar("_A"), TypeVar("_B")
|
||||
_C = _D = TypeVar("_C")
|
||||
@@ -1,12 +0,0 @@
|
||||
import typing
|
||||
from typing import TypeVar
|
||||
|
||||
_T = typing.TypeVar("_T")
|
||||
_P = TypeVar("_P")
|
||||
|
||||
# OK
|
||||
_UsedTypeVar = TypeVar("_UsedTypeVar")
|
||||
def func(arg: _UsedTypeVar) -> _UsedTypeVar: ...
|
||||
|
||||
_A, _B = TypeVar("_A"), TypeVar("_B")
|
||||
_C = _D = TypeVar("_C")
|
||||
@@ -1,19 +0,0 @@
|
||||
import typing
|
||||
from typing import TypeAlias, Literal, Any
|
||||
|
||||
NewAny = Any
|
||||
OptionalStr = typing.Optional[str]
|
||||
Foo = Literal["foo"]
|
||||
IntOrStr = int | str
|
||||
AliasNone = None
|
||||
|
||||
NewAny: typing.TypeAlias = Any
|
||||
OptionalStr: TypeAlias = typing.Optional[str]
|
||||
Foo: typing.TypeAlias = Literal["foo"]
|
||||
IntOrStr: TypeAlias = int | str
|
||||
IntOrFloat: Foo = int | float
|
||||
AliasNone: typing.TypeAlias = None
|
||||
|
||||
# these are ok
|
||||
VarAlias = str
|
||||
AliasFoo = Foo
|
||||
@@ -1,18 +0,0 @@
|
||||
from typing import Literal, Any
|
||||
|
||||
NewAny = Any
|
||||
OptionalStr = typing.Optional[str]
|
||||
Foo = Literal["foo"]
|
||||
IntOrStr = int | str
|
||||
AliasNone = None
|
||||
|
||||
NewAny: typing.TypeAlias = Any
|
||||
OptionalStr: TypeAlias = typing.Optional[str]
|
||||
Foo: typing.TypeAlias = Literal["foo"]
|
||||
IntOrStr: TypeAlias = int | str
|
||||
IntOrFloat: Foo = int | float
|
||||
AliasNone: typing.TypeAlias = None
|
||||
|
||||
# these are ok
|
||||
VarAlias = str
|
||||
AliasFoo = Foo
|
||||
@@ -1,18 +0,0 @@
|
||||
import typing
|
||||
from typing import Protocol
|
||||
|
||||
|
||||
class _Foo(Protocol):
|
||||
bar: int
|
||||
|
||||
|
||||
class _Bar(typing.Protocol):
|
||||
bar: int
|
||||
|
||||
|
||||
# OK
|
||||
class _UsedPrivateProtocol(Protocol):
|
||||
bar: int
|
||||
|
||||
|
||||
def uses__UsedPrivateProtocol(arg: _UsedPrivateProtocol) -> None: ...
|
||||
@@ -1,18 +0,0 @@
|
||||
import typing
|
||||
from typing import Protocol
|
||||
|
||||
|
||||
class _Foo(object, Protocol):
|
||||
bar: int
|
||||
|
||||
|
||||
class _Bar(typing.Protocol):
|
||||
bar: int
|
||||
|
||||
|
||||
# OK
|
||||
class _UsedPrivateProtocol(Protocol):
|
||||
bar: int
|
||||
|
||||
|
||||
def uses__UsedPrivateProtocol(arg: _UsedPrivateProtocol) -> None: ...
|
||||
@@ -1,12 +0,0 @@
|
||||
__all__ = ["A", "B", "C"]
|
||||
|
||||
# Errors
|
||||
__all__.append("D")
|
||||
__all__.extend(["E", "Foo"])
|
||||
__all__.remove("A")
|
||||
|
||||
# OK
|
||||
__all__ += ["D"]
|
||||
foo = ["Hello"]
|
||||
foo.append("World")
|
||||
foo.bar.append("World")
|
||||
@@ -1,12 +0,0 @@
|
||||
__all__ = ["A", "B", "C"]
|
||||
|
||||
# Errors
|
||||
__all__.append("D")
|
||||
__all__.extend(["E", "Foo"])
|
||||
__all__.remove("A")
|
||||
|
||||
# OK
|
||||
__all__ += ["D"]
|
||||
foo = ["Hello"]
|
||||
foo.append("World")
|
||||
foo.bar.append("World")
|
||||
@@ -11,10 +11,6 @@ async def test_ok_trivial_with():
|
||||
with context_manager_under_test():
|
||||
pass
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
with context_manager_under_test():
|
||||
raise ValueError
|
||||
|
||||
with pytest.raises(AttributeError):
|
||||
async with context_manager_under_test():
|
||||
pass
|
||||
@@ -28,16 +24,6 @@ def test_ok_complex_single_call():
|
||||
)
|
||||
|
||||
|
||||
def test_ok_func_and_class():
|
||||
with pytest.raises(AttributeError):
|
||||
class A:
|
||||
pass
|
||||
|
||||
with pytest.raises(AttributeError):
|
||||
def f():
|
||||
pass
|
||||
|
||||
|
||||
def test_error_multiple_statements():
|
||||
with pytest.raises(AttributeError):
|
||||
len([])
|
||||
@@ -61,10 +47,13 @@ async def test_error_complex_statement():
|
||||
while True:
|
||||
[].size
|
||||
|
||||
with pytest.raises(AttributeError):
|
||||
with context_manager_under_test():
|
||||
[].size
|
||||
|
||||
with pytest.raises(AttributeError):
|
||||
async with context_manager_under_test():
|
||||
if True:
|
||||
raise Exception
|
||||
[].size
|
||||
|
||||
|
||||
def test_error_try():
|
||||
|
||||
@@ -100,14 +100,6 @@ if node.module0123456789:
|
||||
):
|
||||
print("Bad module!")
|
||||
|
||||
# SIM102
|
||||
# Regression test for https://github.com/apache/airflow/blob/145b16caaa43f0c42bffd97344df916c602cddde/airflow/configuration.py#L1161
|
||||
if a:
|
||||
if b:
|
||||
if c:
|
||||
print("if")
|
||||
elif d:
|
||||
print("elif")
|
||||
|
||||
# OK
|
||||
if a:
|
||||
@@ -156,12 +148,3 @@ if False:
|
||||
if True:
|
||||
if a:
|
||||
pass
|
||||
|
||||
|
||||
# SIM102
|
||||
def f():
|
||||
if a:
|
||||
pass
|
||||
elif b:
|
||||
if c:
|
||||
d
|
||||
|
||||
@@ -14,12 +14,6 @@ try:
|
||||
except (ValueError, OSError):
|
||||
pass
|
||||
|
||||
# SIM105
|
||||
try:
|
||||
foo()
|
||||
except (ValueError, OSError) as e:
|
||||
pass
|
||||
|
||||
# SIM105
|
||||
try:
|
||||
foo()
|
||||
@@ -100,13 +94,3 @@ def with_comment():
|
||||
foo()
|
||||
except (ValueError, OSError):
|
||||
pass # Trailing comment.
|
||||
|
||||
try:
|
||||
print()
|
||||
except ("not", "an", "exception"):
|
||||
pass
|
||||
|
||||
try:
|
||||
print()
|
||||
except "not an exception":
|
||||
pass
|
||||
|
||||
@@ -23,7 +23,7 @@ elif a:
|
||||
else:
|
||||
b = 2
|
||||
|
||||
# SIM108
|
||||
# OK (false negative)
|
||||
if True:
|
||||
pass
|
||||
else:
|
||||
|
||||
@@ -94,23 +94,3 @@ if result.eofs == "F":
|
||||
errors = 1
|
||||
else:
|
||||
errors = 1
|
||||
|
||||
if a:
|
||||
# Ignore branches with diverging comments because it means we're repeating
|
||||
# the bodies because we have different reasons for each branch
|
||||
x = 1
|
||||
elif c:
|
||||
x = 1
|
||||
|
||||
|
||||
def foo():
|
||||
a = True
|
||||
b = False
|
||||
if a > b: # end-of-line
|
||||
return 3
|
||||
elif a == b:
|
||||
return 3
|
||||
elif a < b: # end-of-line
|
||||
return 4
|
||||
elif b is None:
|
||||
return 4
|
||||
|
||||
@@ -84,15 +84,3 @@ elif func_name == "remove":
|
||||
return "D"
|
||||
elif func_name == "move":
|
||||
return "MV"
|
||||
|
||||
# OK
|
||||
def no_return_in_else(platform):
|
||||
if platform == "linux":
|
||||
return "auditwheel repair -w {dest_dir} {wheel}"
|
||||
elif platform == "macos":
|
||||
return "delocate-wheel --require-archs {delocate_archs} -w {dest_dir} -v {wheel}"
|
||||
elif platform == "windows":
|
||||
return ""
|
||||
else:
|
||||
msg = f"Unknown platform: {platform!r}"
|
||||
raise ValueError(msg)
|
||||
|
||||
@@ -1,19 +1,11 @@
|
||||
key in obj.keys() # SIM118
|
||||
|
||||
key not in obj.keys() # SIM118
|
||||
|
||||
foo["bar"] in obj.keys() # SIM118
|
||||
|
||||
foo["bar"] not in obj.keys() # SIM118
|
||||
|
||||
foo['bar'] in obj.keys() # SIM118
|
||||
|
||||
foo['bar'] not in obj.keys() # SIM118
|
||||
|
||||
foo() in obj.keys() # SIM118
|
||||
|
||||
foo() not in obj.keys() # SIM118
|
||||
|
||||
for key in obj.keys(): # SIM118
|
||||
pass
|
||||
|
||||
|
||||
@@ -38,15 +38,6 @@ if key in a_dict:
|
||||
else:
|
||||
vars[idx] = "defaultß9💣2ℝ6789ß9💣2ℝ6789ß9💣2ℝ6789ß9💣2ℝ6789ß9💣2ℝ6789"
|
||||
|
||||
# SIM401
|
||||
if foo():
|
||||
pass
|
||||
else:
|
||||
if key in a_dict:
|
||||
vars[idx] = a_dict[key]
|
||||
else:
|
||||
vars[idx] = "default"
|
||||
|
||||
###
|
||||
# Negative cases
|
||||
###
|
||||
@@ -114,3 +105,12 @@ elif key in a_dict:
|
||||
vars[idx] = a_dict[key]
|
||||
else:
|
||||
vars[idx] = "default"
|
||||
|
||||
# OK (false negative for nested else)
|
||||
if foo():
|
||||
pass
|
||||
else:
|
||||
if key in a_dict:
|
||||
vars[idx] = a_dict[key]
|
||||
else:
|
||||
vars[idx] = "default"
|
||||
|
||||
21
crates/ruff/resources/test/fixtures/flake8_type_checking/TCH200_0.py
vendored
Normal file
21
crates/ruff/resources/test/fixtures/flake8_type_checking/TCH200_0.py
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
import module
|
||||
from module import Class
|
||||
|
||||
|
||||
def f(var: Class) -> Class:
|
||||
x: Class
|
||||
|
||||
|
||||
def f(var: module.Class) -> module.Class:
|
||||
x: module.Class
|
||||
|
||||
|
||||
def f():
|
||||
print(Class)
|
||||
|
||||
|
||||
def f():
|
||||
print(module.Class)
|
||||
6
crates/ruff/resources/test/fixtures/flake8_type_checking/TCH200_1.py
vendored
Normal file
6
crates/ruff/resources/test/fixtures/flake8_type_checking/TCH200_1.py
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
Class = ...
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from module import Class
|
||||
@@ -1,15 +0,0 @@
|
||||
from pathlib import Path, PurePath
|
||||
from pathlib import Path as pth
|
||||
|
||||
# match
|
||||
_ = Path(".")
|
||||
_ = pth(".")
|
||||
_ = PurePath(".")
|
||||
_ = Path("")
|
||||
|
||||
# no match
|
||||
_ = Path()
|
||||
print(".")
|
||||
Path("file.txt")
|
||||
Path(".", "folder")
|
||||
PurePath(".", "folder")
|
||||
@@ -1,14 +0,0 @@
|
||||
import os.path
|
||||
from pathlib import Path
|
||||
from os.path import getsize
|
||||
|
||||
|
||||
os.path.getsize("filename")
|
||||
os.path.getsize(b"filename")
|
||||
os.path.getsize(Path("filename"))
|
||||
os.path.getsize(__file__)
|
||||
|
||||
getsize("filename")
|
||||
getsize(b"filename")
|
||||
getsize(Path("filename"))
|
||||
getsize(__file__)
|
||||
@@ -1,12 +0,0 @@
|
||||
import os.path
|
||||
from pathlib import Path
|
||||
from os.path import getatime
|
||||
|
||||
os.path.getatime("filename")
|
||||
os.path.getatime(b"filename")
|
||||
os.path.getatime(Path("filename"))
|
||||
|
||||
|
||||
getatime("filename")
|
||||
getatime(b"filename")
|
||||
getatime(Path("filename"))
|
||||
@@ -1,13 +0,0 @@
|
||||
import os.path
|
||||
from pathlib import Path
|
||||
from os.path import getmtime
|
||||
|
||||
|
||||
os.path.getmtime("filename")
|
||||
os.path.getmtime(b"filename")
|
||||
os.path.getmtime(Path("filename"))
|
||||
|
||||
|
||||
getmtime("filename")
|
||||
getmtime(b"filename")
|
||||
getmtime(Path("filename"))
|
||||
@@ -1,12 +0,0 @@
|
||||
import os.path
|
||||
from pathlib import Path
|
||||
from os.path import getctime
|
||||
|
||||
|
||||
os.path.getctime("filename")
|
||||
os.path.getctime(b"filename")
|
||||
os.path.getctime(Path("filename"))
|
||||
|
||||
getctime("filename")
|
||||
getctime(b"filename")
|
||||
getctime(Path("filename"))
|
||||
@@ -1,20 +0,0 @@
|
||||
import os
|
||||
from os import sep
|
||||
|
||||
|
||||
file_name = "foo/bar"
|
||||
|
||||
# PTH206
|
||||
"foo/bar/".split(os.sep)
|
||||
"foo/bar/".split(sep=os.sep)
|
||||
"foo/bar/".split(os.sep)[-1]
|
||||
"foo/bar/".split(os.sep)[-2]
|
||||
"foo/bar/".split(os.sep)[-2:]
|
||||
"fizz/buzz".split(sep)
|
||||
"fizz/buzz".split(sep)[-1]
|
||||
os.path.splitext("path/to/hello_world.py")[0].split(os.sep)[-1]
|
||||
file_name.split(os.sep)
|
||||
(os.path.abspath(file_name)).split(os.sep)
|
||||
|
||||
# OK
|
||||
"foo/bar/".split("/")
|
||||
@@ -1,11 +0,0 @@
|
||||
import os
|
||||
import glob
|
||||
from glob import glob as search
|
||||
|
||||
|
||||
extensions_dir = "./extensions"
|
||||
|
||||
# PTH207
|
||||
glob.glob(os.path.join(extensions_dir, "ops", "autograd", "*.cpp"))
|
||||
list(glob.iglob(os.path.join(extensions_dir, "ops", "autograd", "*.cpp")))
|
||||
search("*.png")
|
||||
@@ -2,7 +2,6 @@ import os
|
||||
import os.path
|
||||
|
||||
p = "/foo"
|
||||
q = "bar"
|
||||
|
||||
a = os.path.abspath(p)
|
||||
aa = os.chmod(p)
|
||||
@@ -22,9 +21,7 @@ bbbbb = os.path.islink(p)
|
||||
os.readlink(p)
|
||||
os.stat(p)
|
||||
os.path.isabs(p)
|
||||
os.path.join(p, q)
|
||||
os.sep.join([p, q])
|
||||
os.sep.join((p, q))
|
||||
os.path.join(p)
|
||||
os.path.basename(p)
|
||||
os.path.dirname(p)
|
||||
os.path.samefile(p)
|
||||
|
||||
@@ -2,7 +2,6 @@ import os as foo
|
||||
import os.path as foo_p
|
||||
|
||||
p = "/foo"
|
||||
q = "bar"
|
||||
|
||||
a = foo_p.abspath(p)
|
||||
aa = foo.chmod(p)
|
||||
@@ -22,9 +21,7 @@ bbbbb = foo_p.islink(p)
|
||||
foo.readlink(p)
|
||||
foo.stat(p)
|
||||
foo_p.isabs(p)
|
||||
foo_p.join(p, q)
|
||||
foo.sep.join([p, q])
|
||||
foo.sep.join((p, q))
|
||||
foo_p.join(p)
|
||||
foo_p.basename(p)
|
||||
foo_p.dirname(p)
|
||||
foo_p.samefile(p)
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
from os import chmod, mkdir, makedirs, rename, replace, rmdir, sep
|
||||
from os import chmod, mkdir, makedirs, rename, replace, rmdir
|
||||
from os import remove, unlink, getcwd, readlink, stat
|
||||
from os.path import abspath, exists, expanduser, isdir, isfile, islink
|
||||
from os.path import isabs, join, basename, dirname, samefile, splitext
|
||||
|
||||
p = "/foo"
|
||||
q = "bar"
|
||||
|
||||
a = abspath(p)
|
||||
aa = chmod(p)
|
||||
@@ -24,9 +23,7 @@ bbbbb = islink(p)
|
||||
readlink(p)
|
||||
stat(p)
|
||||
isabs(p)
|
||||
join(p, q)
|
||||
sep.join((p, q))
|
||||
sep.join([p, q])
|
||||
join(p)
|
||||
basename(p)
|
||||
dirname(p)
|
||||
samefile(p)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from os import chmod as xchmod, mkdir as xmkdir, sep as s
|
||||
from os import chmod as xchmod, mkdir as xmkdir
|
||||
from os import makedirs as xmakedirs, rename as xrename, replace as xreplace
|
||||
from os import rmdir as xrmdir, remove as xremove, unlink as xunlink
|
||||
from os import getcwd as xgetcwd, readlink as xreadlink, stat as xstat
|
||||
@@ -9,7 +9,6 @@ from os.path import join as xjoin, basename as xbasename, dirname as xdirname
|
||||
from os.path import samefile as xsamefile, splitext as xsplitext
|
||||
|
||||
p = "/foo"
|
||||
q = "bar"
|
||||
|
||||
a = xabspath(p)
|
||||
aa = xchmod(p)
|
||||
@@ -29,9 +28,7 @@ bbbbb = xislink(p)
|
||||
xreadlink(p)
|
||||
xstat(p)
|
||||
xisabs(p)
|
||||
xjoin(p, q)
|
||||
s.join((p, q))
|
||||
s.join([p, q])
|
||||
xjoin(p)
|
||||
xbasename(p)
|
||||
xdirname(p)
|
||||
xsamefile(p)
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
if "sdist" in cmds:
|
||||
_sdist = cmds["sdist"]
|
||||
elif "setuptools" in sys.modules:
|
||||
from setuptools.command.sdist import sdist as _sdist
|
||||
else:
|
||||
from setuptools.command.sdist import sdist as _sdist
|
||||
from distutils.command.sdist import sdist as _sdist
|
||||
@@ -1,7 +0,0 @@
|
||||
match 1:
|
||||
case 1:
|
||||
import sys
|
||||
import os
|
||||
case 2:
|
||||
import collections
|
||||
import abc
|
||||
@@ -1 +1 @@
|
||||
broken "§=($/=()
|
||||
broken "§=($/=(")
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
import pandas as pd
|
||||
|
||||
|
||||
data = pd.Series(range(1000))
|
||||
|
||||
# PD101
|
||||
data.nunique() <= 1
|
||||
data.nunique(dropna=True) <= 1
|
||||
data.nunique(dropna=False) <= 1
|
||||
data.nunique() == 1
|
||||
data.nunique(dropna=True) == 1
|
||||
data.nunique(dropna=False) == 1
|
||||
data.nunique() != 1
|
||||
data.nunique(dropna=True) != 1
|
||||
data.nunique(dropna=False) != 1
|
||||
data.nunique() > 1
|
||||
data.dropna().nunique() == 1
|
||||
data[data.notnull()].nunique() == 1
|
||||
|
||||
# No violation of this rule
|
||||
data.nunique() == 0 # empty
|
||||
data.nunique() >= 1 # not-empty
|
||||
data.nunique() < 1 # empty
|
||||
data.nunique() == 2 # not constant
|
||||
data.unique() == 1 # not `nunique`
|
||||
|
||||
{"hello": "world"}.nunique() == 1 # no pd.Series
|
||||
@@ -1,20 +0,0 @@
|
||||
import pandas as pd
|
||||
|
||||
# Errors.
|
||||
df = pd.read_table("data.csv", sep=",")
|
||||
df = pd.read_table("data.csv", sep=",", header=0)
|
||||
filename = "data.csv"
|
||||
df = pd.read_table(filename, sep=",")
|
||||
df = pd.read_table(filename, sep=",", header=0)
|
||||
|
||||
# Non-errors.
|
||||
df = pd.read_csv("data.csv")
|
||||
df = pd.read_table("data.tsv")
|
||||
df = pd.read_table("data.tsv", sep="\t")
|
||||
df = pd.read_table("data.tsv", sep=",,")
|
||||
df = pd.read_table("data.tsv", sep=", ")
|
||||
df = pd.read_table("data.tsv", sep=" ,")
|
||||
df = pd.read_table("data.tsv", sep=" , ")
|
||||
not_pd.read_table("data.csv", sep=",")
|
||||
data = read_table("data.csv", sep=",")
|
||||
data = read_table
|
||||
@@ -1,101 +1,71 @@
|
||||
some_dict = {"a": 12, "b": 32, "c": 44}
|
||||
|
||||
|
||||
def f():
|
||||
for _, value in some_dict.items(): # PERF102
|
||||
print(value)
|
||||
for _, value in some_dict.items(): # PERF102
|
||||
print(value)
|
||||
|
||||
|
||||
def f():
|
||||
for key, _ in some_dict.items(): # PERF102
|
||||
print(key)
|
||||
for key, _ in some_dict.items(): # PERF102
|
||||
print(key)
|
||||
|
||||
|
||||
def f():
|
||||
for weird_arg_name, _ in some_dict.items(): # PERF102
|
||||
print(weird_arg_name)
|
||||
for weird_arg_name, _ in some_dict.items(): # PERF102
|
||||
print(weird_arg_name)
|
||||
|
||||
|
||||
def f():
|
||||
for name, (_, _) in some_dict.items(): # PERF102
|
||||
print(name)
|
||||
for name, (_, _) in some_dict.items(): # PERF102
|
||||
pass
|
||||
|
||||
|
||||
def f():
|
||||
for name, (value1, _) in some_dict.items(): # OK
|
||||
print(name, value1)
|
||||
for name, (value1, _) in some_dict.items(): # OK
|
||||
pass
|
||||
|
||||
|
||||
def f():
|
||||
for (key1, _), (_, _) in some_dict.items(): # PERF102
|
||||
print(key1)
|
||||
for (key1, _), (_, _) in some_dict.items(): # PERF102
|
||||
pass
|
||||
|
||||
|
||||
def f():
|
||||
for (_, (_, _)), (value, _) in some_dict.items(): # PERF102
|
||||
print(value)
|
||||
for (_, (_, _)), (value, _) in some_dict.items(): # PERF102
|
||||
pass
|
||||
|
||||
|
||||
def f():
|
||||
for (_, key2), (value1, _) in some_dict.items(): # OK
|
||||
print(key2, value1)
|
||||
for (_, key2), (value1, _) in some_dict.items(): # OK
|
||||
pass
|
||||
|
||||
|
||||
def f():
|
||||
for ((_, key2), (value1, _)) in some_dict.items(): # OK
|
||||
print(key2, value1)
|
||||
for ((_, key2), (value1, _)) in some_dict.items(): # OK
|
||||
pass
|
||||
|
||||
|
||||
def f():
|
||||
for ((_, key2), (_, _)) in some_dict.items(): # PERF102
|
||||
print(key2)
|
||||
for ((_, key2), (_, _)) in some_dict.items(): # PERF102
|
||||
pass
|
||||
|
||||
|
||||
def f():
|
||||
for (_, _, _, variants), (r_language, _, _, _) in some_dict.items(): # OK
|
||||
print(variants, r_language)
|
||||
for (_, _, _, variants), (r_language, _, _, _) in some_dict.items(): # OK
|
||||
pass
|
||||
|
||||
|
||||
def f():
|
||||
for (_, _, (_, variants)), (_, (_, (r_language, _))) in some_dict.items(): # OK
|
||||
print(variants, r_language)
|
||||
for (_, _, (_, variants)), (_, (_, (r_language, _))) in some_dict.items(): # OK
|
||||
pass
|
||||
|
||||
|
||||
def f():
|
||||
for key, value in some_dict.items(): # OK
|
||||
print(key, value)
|
||||
for key, value in some_dict.items(): # OK
|
||||
print(key, value)
|
||||
|
||||
|
||||
def f():
|
||||
for _, value in some_dict.items(12): # OK
|
||||
print(value)
|
||||
for _, value in some_dict.items(12): # OK
|
||||
print(value)
|
||||
|
||||
|
||||
def f():
|
||||
for key in some_dict.keys(): # OK
|
||||
print(key)
|
||||
for key in some_dict.keys(): # OK
|
||||
print(key)
|
||||
|
||||
|
||||
def f():
|
||||
for value in some_dict.values(): # OK
|
||||
print(value)
|
||||
for value in some_dict.values(): # OK
|
||||
print(value)
|
||||
|
||||
|
||||
def f():
|
||||
for name, (_, _) in (some_function()).items(): # PERF102
|
||||
print(name)
|
||||
for name, (_, _) in (some_function()).items(): # PERF102
|
||||
pass
|
||||
|
||||
|
||||
def f():
|
||||
for name, (_, _) in (some_function().some_attribute).items(): # PERF102
|
||||
print(name)
|
||||
|
||||
|
||||
def f():
|
||||
for name, unused_value in some_dict.items(): # PERF102
|
||||
print(name)
|
||||
|
||||
|
||||
def f():
|
||||
for unused_name, value in some_dict.items(): # PERF102
|
||||
print(value)
|
||||
for name, (_, _) in (some_function().some_attribute).items(): # PERF102
|
||||
pass
|
||||
|
||||
@@ -41,5 +41,3 @@ regex = '\w' # noqa
|
||||
regex = '''
|
||||
\w
|
||||
''' # noqa
|
||||
|
||||
regex = '\\\_'
|
||||
|
||||
@@ -23,5 +23,3 @@ a = []
|
||||
'%s %s' % (*a,)
|
||||
k = {}
|
||||
'%(k)s' % {**k}
|
||||
'%s' % [1, 2, 3]
|
||||
'%s' % {1, 2, 3}
|
||||
|
||||
@@ -1,11 +1,6 @@
|
||||
if (1, 2):
|
||||
pass
|
||||
|
||||
if (3, 4):
|
||||
pass
|
||||
elif foo:
|
||||
pass
|
||||
|
||||
for _ in range(5):
|
||||
if True:
|
||||
pass
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
# Regression test for branch detection from
|
||||
# https://github.com/pypa/build/blob/5800521541e5e749d4429617420d1ef8cdb40b46/src/build/_importlib.py
|
||||
import sys
|
||||
|
||||
if sys.version_info < (3, 8):
|
||||
import importlib_metadata as metadata
|
||||
elif sys.version_info < (3, 9, 10) or (3, 10, 0) <= sys.version_info < (3, 10, 2):
|
||||
try:
|
||||
import importlib_metadata as metadata
|
||||
except ModuleNotFoundError:
|
||||
from importlib import metadata
|
||||
else:
|
||||
from importlib import metadata
|
||||
|
||||
__all__ = ["metadata"]
|
||||
@@ -1,6 +0,0 @@
|
||||
class Class:
|
||||
def func(self):
|
||||
pass
|
||||
|
||||
def func(self):
|
||||
pass
|
||||
@@ -1,11 +0,0 @@
|
||||
"""Test case: `Literal` with `__future__` annotations."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Literal, Final
|
||||
|
||||
from typing_extensions import assert_type
|
||||
|
||||
CONSTANT: Final = "ns"
|
||||
|
||||
assert_type(CONSTANT, Literal["ns"])
|
||||
@@ -25,41 +25,3 @@ def dec(x):
|
||||
def f():
|
||||
dec = 1
|
||||
return dec
|
||||
|
||||
|
||||
class Class:
|
||||
def f(self):
|
||||
print(my_var)
|
||||
my_var = 1
|
||||
|
||||
|
||||
class Class:
|
||||
my_var = 0
|
||||
|
||||
def f(self):
|
||||
print(my_var)
|
||||
my_var = 1
|
||||
|
||||
|
||||
import sys
|
||||
|
||||
|
||||
def main():
|
||||
print(sys.argv)
|
||||
|
||||
try:
|
||||
3 / 0
|
||||
except ZeroDivisionError:
|
||||
import sys
|
||||
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
import sys
|
||||
|
||||
|
||||
def main():
|
||||
print(sys.argv)
|
||||
|
||||
for sys in range(5):
|
||||
pass
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
x = 1 # type: ignore
|
||||
x = 1 # type:ignore
|
||||
x = 1 # type: ignore[attr-defined] # type: ignore
|
||||
x = 1 # type: ignoreme # type: ignore
|
||||
|
||||
x = 1
|
||||
x = 1 # type ignore
|
||||
@@ -47,17 +47,3 @@ def not_ok1():
|
||||
pass
|
||||
else:
|
||||
pass
|
||||
|
||||
|
||||
# Regression test for https://github.com/apache/airflow/blob/f1e1cdcc3b2826e68ba133f350300b5065bbca33/airflow/models/dag.py#L1737
|
||||
def not_ok2():
|
||||
if True:
|
||||
print(1)
|
||||
elif True:
|
||||
print(2)
|
||||
else:
|
||||
if True:
|
||||
print(3)
|
||||
else:
|
||||
print(4)
|
||||
|
||||
|
||||
@@ -80,8 +80,3 @@ def multiple_assignment():
|
||||
global CONSTANT # [global-statement]
|
||||
CONSTANT = 1
|
||||
CONSTANT = 2
|
||||
|
||||
|
||||
def no_assignment():
|
||||
"""Shouldn't warn"""
|
||||
global CONSTANT
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
foo = 1
|
||||
bar = 2
|
||||
baz = 3
|
||||
|
||||
# Errors.
|
||||
foo = foo
|
||||
bar = bar
|
||||
foo, bar = foo, bar
|
||||
bar, foo = bar, foo
|
||||
(foo, bar) = (foo, bar)
|
||||
(bar, foo) = (bar, foo)
|
||||
foo, (bar, baz) = foo, (bar, baz)
|
||||
bar, (foo, baz) = bar, (foo, baz)
|
||||
(foo, bar), baz = (foo, bar), baz
|
||||
(foo, (bar, baz)) = (foo, (bar, baz))
|
||||
foo, bar = foo, 1
|
||||
bar, foo = bar, 1
|
||||
(foo, bar) = (foo, 1)
|
||||
(bar, foo) = (bar, 1)
|
||||
foo, (bar, baz) = foo, (bar, 1)
|
||||
bar, (foo, baz) = bar, (foo, 1)
|
||||
(foo, bar), baz = (foo, bar), 1
|
||||
(foo, (bar, baz)) = (foo, (bar, 1))
|
||||
foo: int = foo
|
||||
bar: int = bar
|
||||
|
||||
# Non-errors.
|
||||
foo = bar
|
||||
bar = foo
|
||||
foo, bar = bar, foo
|
||||
foo, bar = bar, foo
|
||||
(foo, bar) = (bar, foo)
|
||||
foo, bar = bar, 1
|
||||
bar, foo = foo, 1
|
||||
foo: int = bar
|
||||
bar: int = 1
|
||||
|
||||
|
||||
class Foo:
|
||||
foo = foo
|
||||
bar = bar
|
||||
@@ -1,18 +0,0 @@
|
||||
import subprocess
|
||||
|
||||
|
||||
def foo():
|
||||
pass
|
||||
|
||||
|
||||
# Errors.
|
||||
subprocess.Popen(preexec_fn=foo)
|
||||
subprocess.Popen(["ls"], preexec_fn=foo)
|
||||
subprocess.Popen(preexec_fn=lambda: print("Hello, world!"))
|
||||
subprocess.Popen(["ls"], preexec_fn=lambda: print("Hello, world!"))
|
||||
|
||||
# Non-errors.
|
||||
subprocess.Popen()
|
||||
subprocess.Popen(["ls"])
|
||||
subprocess.Popen(preexec_fn=None) # None is the default.
|
||||
subprocess.Popen(["ls"], preexec_fn=None) # None is the default.
|
||||
@@ -1,4 +0,0 @@
|
||||
print('Hello world')
|
||||
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
@@ -4,9 +4,23 @@ import typing
|
||||
# with complex annotations
|
||||
MyType = NamedTuple("MyType", [("a", int), ("b", tuple[str, ...])])
|
||||
|
||||
# with default values as list
|
||||
MyType = NamedTuple(
|
||||
"MyType",
|
||||
[("a", int), ("b", str), ("c", list[bool])],
|
||||
defaults=["foo", [True]],
|
||||
)
|
||||
|
||||
# with namespace
|
||||
MyType = typing.NamedTuple("MyType", [("a", int), ("b", str)])
|
||||
|
||||
# too many default values (OK)
|
||||
MyType = NamedTuple(
|
||||
"MyType",
|
||||
[("a", int), ("b", str)],
|
||||
defaults=[1, "bar", "baz"],
|
||||
)
|
||||
|
||||
# invalid identifiers (OK)
|
||||
MyType = NamedTuple("MyType", [("x-y", int), ("b", tuple[str, ...])])
|
||||
|
||||
@@ -15,10 +29,3 @@ MyType = typing.NamedTuple("MyType")
|
||||
|
||||
# empty fields
|
||||
MyType = typing.NamedTuple("MyType", [])
|
||||
|
||||
# keywords
|
||||
MyType = typing.NamedTuple("MyType", a=int, b=tuple[str, ...])
|
||||
|
||||
# unfixable
|
||||
MyType = typing.NamedTuple("MyType", [("a", int)], [("b", str)])
|
||||
MyType = typing.NamedTuple("MyType", [("a", int)], b=str)
|
||||
|
||||
@@ -15,22 +15,7 @@ bytes("foo", **a)
|
||||
bytes(b"foo"
|
||||
b"bar")
|
||||
bytes("foo")
|
||||
bytes(1)
|
||||
f"{f'{str()}'}"
|
||||
int(1.0)
|
||||
int("1")
|
||||
int(b"11")
|
||||
int(10, base=2)
|
||||
int("10", base=2)
|
||||
int("10", 2)
|
||||
float("1.0")
|
||||
float(b"1.0")
|
||||
bool(1)
|
||||
bool(0)
|
||||
bool("foo")
|
||||
bool("")
|
||||
bool(b"")
|
||||
bool(1.0)
|
||||
|
||||
# These become string or byte literals
|
||||
str()
|
||||
@@ -42,10 +27,3 @@ bytes(b"foo")
|
||||
bytes(b"""
|
||||
foo""")
|
||||
f"{str()}"
|
||||
int()
|
||||
int(1)
|
||||
float()
|
||||
float(1.0)
|
||||
bool()
|
||||
bool(True)
|
||||
bool(False)
|
||||
|
||||
@@ -62,16 +62,6 @@ print("foo {} ".format(x))
|
||||
1111111111111111111111111111111111111111111111111111111111111111111111111,
|
||||
)
|
||||
|
||||
"""
|
||||
{}
|
||||
""".format(1)
|
||||
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa = """
|
||||
{}
|
||||
""".format(
|
||||
111111
|
||||
)
|
||||
|
||||
###
|
||||
# Non-errors
|
||||
###
|
||||
@@ -109,37 +99,6 @@ r'"\N{snowman} {}".format(a)'
|
||||
11111111111111111111111111111111111111111111111111111111111111111111111111,
|
||||
)
|
||||
|
||||
"""
|
||||
{}
|
||||
{}
|
||||
{}
|
||||
""".format(
|
||||
1,
|
||||
2,
|
||||
111111111111111111111111111111111111111111111111111111111111111111111111111111111111111,
|
||||
)
|
||||
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa = """{}
|
||||
""".format(
|
||||
111111
|
||||
)
|
||||
|
||||
"{}".format(
|
||||
[
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
]
|
||||
)
|
||||
|
||||
"{a}".format(
|
||||
a=[
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
]
|
||||
)
|
||||
|
||||
async def c():
|
||||
return "{}".format(await 3)
|
||||
|
||||
|
||||
@@ -7,20 +7,20 @@ if True:
|
||||
|
||||
if True:
|
||||
if foo:
|
||||
print()
|
||||
pass
|
||||
elif sys.version_info < (3, 3):
|
||||
cmd = [sys.executable, "-m", "test.regrtest"]
|
||||
|
||||
if True:
|
||||
if foo:
|
||||
print()
|
||||
pass
|
||||
elif sys.version_info < (3, 3):
|
||||
cmd = [sys.executable, "-m", "test.regrtest"]
|
||||
elif foo:
|
||||
cmd = [sys.executable, "-m", "test", "-j0"]
|
||||
|
||||
if foo:
|
||||
print()
|
||||
pass
|
||||
elif sys.version_info < (3, 3):
|
||||
cmd = [sys.executable, "-m", "test.regrtest"]
|
||||
|
||||
@@ -28,7 +28,7 @@ if True:
|
||||
cmd = [sys.executable, "-m", "test.regrtest"]
|
||||
|
||||
if foo:
|
||||
print()
|
||||
pass
|
||||
elif sys.version_info < (3, 3):
|
||||
cmd = [sys.executable, "-m", "test.regrtest"]
|
||||
else:
|
||||
|
||||
@@ -34,23 +34,11 @@ list(x)[::]
|
||||
[i for i in x][::2]
|
||||
[i for i in x][::]
|
||||
|
||||
# RUF015 (doesn't mirror the underlying list)
|
||||
# OK (doesn't mirror the underlying list)
|
||||
[i + 1 for i in x][0]
|
||||
[i for i in x if i > 5][0]
|
||||
[(i, i + 1) for i in x][0]
|
||||
|
||||
# RUF015 (multiple generators)
|
||||
# OK (multiple generators)
|
||||
y = range(10)
|
||||
[i + j for i in x for j in y][0]
|
||||
|
||||
# RUF015
|
||||
list(range(10))[0]
|
||||
list(x.y)[0]
|
||||
list(x["y"])[0]
|
||||
|
||||
# RUF015 (multi-line)
|
||||
revision_heads_map_ast = [
|
||||
a
|
||||
for a in revision_heads_map_ast_obj.body
|
||||
if isinstance(a, ast.Assign) and a.targets[0].id == "REVISION_HEADS_MAP"
|
||||
][0]
|
||||
|
||||
@@ -230,15 +230,6 @@ def incorrect_multi_conditional(arg1, arg2):
|
||||
raise Exception("...") # should be typeerror
|
||||
|
||||
|
||||
def multiple_is_instance_checks(some_arg):
|
||||
if isinstance(some_arg, str):
|
||||
pass
|
||||
elif isinstance(some_arg, int):
|
||||
pass
|
||||
else:
|
||||
raise Exception("...") # should be typeerror
|
||||
|
||||
|
||||
class MyCustomTypeValidation(Exception):
|
||||
pass
|
||||
|
||||
@@ -305,17 +296,6 @@ def multiple_ifs(some_args):
|
||||
pass
|
||||
|
||||
|
||||
def else_body(obj):
|
||||
if isinstance(obj, datetime.timedelta):
|
||||
return "TimeDelta"
|
||||
elif isinstance(obj, relativedelta.relativedelta):
|
||||
return "RelativeDelta"
|
||||
elif isinstance(obj, CronExpression):
|
||||
return "CronExpression"
|
||||
else:
|
||||
raise Exception(f"Unknown object type: {obj.__class__.__name__}")
|
||||
|
||||
|
||||
def early_return():
|
||||
if isinstance(this, some_type):
|
||||
if x in this:
|
||||
|
||||
@@ -4,10 +4,9 @@ use anyhow::{bail, Result};
|
||||
use libcst_native::{
|
||||
Codegen, CodegenState, ImportNames, ParenthesizableWhitespace, SmallStatement, Statement,
|
||||
};
|
||||
use ruff_python_ast::{Ranged, Stmt};
|
||||
use rustpython_parser::ast::{Ranged, Stmt};
|
||||
|
||||
use ruff_python_codegen::Stylist;
|
||||
use ruff_source_file::Locator;
|
||||
use ruff_python_ast::source_code::{Locator, Stylist};
|
||||
|
||||
use crate::cst::helpers::compose_module_path;
|
||||
use crate::cst::matchers::match_statement;
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
//! Interface for generating autofix edits from higher-level actions (e.g., "remove an argument").
|
||||
use anyhow::{bail, Result};
|
||||
use ruff_python_ast::{self as ast, ExceptHandler, Expr, Keyword, Ranged, Stmt};
|
||||
use ruff_python_parser::{lexer, Mode};
|
||||
use ruff_text_size::{TextLen, TextRange, TextSize};
|
||||
use rustpython_parser::ast::{self, ExceptHandler, Expr, Keyword, Ranged, Stmt};
|
||||
use rustpython_parser::{lexer, Mode};
|
||||
|
||||
use ruff_diagnostics::Edit;
|
||||
use ruff_python_codegen::Stylist;
|
||||
use ruff_python_index::Indexer;
|
||||
use ruff_python_trivia::{has_leading_content, is_python_whitespace, PythonWhitespace};
|
||||
use ruff_source_file::{Locator, NewlineWithTrailingNewline};
|
||||
use ruff_python_ast::helpers;
|
||||
use ruff_python_ast::source_code::{Indexer, Locator, Stylist};
|
||||
use ruff_python_whitespace::{is_python_whitespace, NewlineWithTrailingNewline, PythonWhitespace};
|
||||
|
||||
use crate::autofix::codemods;
|
||||
|
||||
@@ -42,9 +41,11 @@ pub(crate) fn delete_stmt(
|
||||
if let Some(semicolon) = trailing_semicolon(stmt.end(), locator) {
|
||||
let next = next_stmt_break(semicolon, locator);
|
||||
Edit::deletion(stmt.start(), next)
|
||||
} else if has_leading_content(stmt.start(), locator) {
|
||||
} else if helpers::has_leading_content(stmt.start(), locator) {
|
||||
Edit::range_deletion(stmt.range())
|
||||
} else if let Some(start) = indexer.preceded_by_continuations(stmt.start(), locator) {
|
||||
} else if let Some(start) =
|
||||
helpers::preceded_by_continuations(stmt.start(), locator, indexer)
|
||||
{
|
||||
Edit::range_deletion(TextRange::new(start, stmt.end()))
|
||||
} else {
|
||||
let range = locator.full_lines_range(stmt.range());
|
||||
@@ -189,24 +190,12 @@ fn is_lone_child(child: &Stmt, parent: &Stmt) -> bool {
|
||||
}
|
||||
Stmt::For(ast::StmtFor { body, orelse, .. })
|
||||
| Stmt::AsyncFor(ast::StmtAsyncFor { body, orelse, .. })
|
||||
| Stmt::While(ast::StmtWhile { body, orelse, .. }) => {
|
||||
| Stmt::While(ast::StmtWhile { body, orelse, .. })
|
||||
| Stmt::If(ast::StmtIf { body, orelse, .. }) => {
|
||||
if is_only(body, child) || is_only(orelse, child) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
Stmt::If(ast::StmtIf {
|
||||
body,
|
||||
elif_else_clauses,
|
||||
..
|
||||
}) => {
|
||||
if is_only(body, child)
|
||||
|| elif_else_clauses
|
||||
.iter()
|
||||
.any(|ast::ElifElseClause { body, .. }| is_only(body, child))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
Stmt::Try(ast::StmtTry {
|
||||
body,
|
||||
handlers,
|
||||
@@ -294,11 +283,11 @@ fn next_stmt_break(semicolon: TextSize, locator: &Locator) -> TextSize {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use anyhow::Result;
|
||||
use ruff_python_ast::{Ranged, Suite};
|
||||
use ruff_python_parser::Parse;
|
||||
use ruff_text_size::TextSize;
|
||||
use rustpython_parser::ast::{Ranged, Suite};
|
||||
use rustpython_parser::Parse;
|
||||
|
||||
use ruff_source_file::Locator;
|
||||
use ruff_python_ast::source_code::Locator;
|
||||
|
||||
use crate::autofix::edits::{next_stmt_break, trailing_semicolon};
|
||||
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
use std::collections::BTreeSet;
|
||||
|
||||
use itertools::Itertools;
|
||||
use nohash_hasher::IntSet;
|
||||
use ruff_text_size::{TextLen, TextRange, TextSize};
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
use rustc_hash::FxHashMap;
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Edit, Fix, IsolationLevel};
|
||||
use ruff_source_file::Locator;
|
||||
use ruff_python_ast::source_code::Locator;
|
||||
|
||||
use crate::autofix::source_map::SourceMap;
|
||||
use crate::linter::FixTable;
|
||||
@@ -46,7 +47,7 @@ fn apply_fixes<'a>(
|
||||
let mut output = String::with_capacity(locator.len());
|
||||
let mut last_pos: Option<TextSize> = None;
|
||||
let mut applied: BTreeSet<&Edit> = BTreeSet::default();
|
||||
let mut isolated: FxHashSet<u32> = FxHashSet::default();
|
||||
let mut isolated: IntSet<u32> = IntSet::default();
|
||||
let mut fixed = FxHashMap::default();
|
||||
let mut source_map = SourceMap::default();
|
||||
|
||||
@@ -146,7 +147,7 @@ mod tests {
|
||||
use ruff_diagnostics::Diagnostic;
|
||||
use ruff_diagnostics::Edit;
|
||||
use ruff_diagnostics::Fix;
|
||||
use ruff_source_file::Locator;
|
||||
use ruff_python_ast::source_code::Locator;
|
||||
|
||||
use crate::autofix::source_map::SourceMarker;
|
||||
use crate::autofix::{apply_fixes, FixResult};
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
use ruff_python_ast::{Arg, Ranged};
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::codes::Rule;
|
||||
use crate::rules::{flake8_builtins, pep8_naming, pycodestyle};
|
||||
|
||||
/// Run lint rules over an [`Arg`] syntax node.
|
||||
pub(crate) fn argument(arg: &Arg, checker: &mut Checker) {
|
||||
if checker.enabled(Rule::AmbiguousVariableName) {
|
||||
if let Some(diagnostic) = pycodestyle::rules::ambiguous_variable_name(&arg.arg, arg.range())
|
||||
{
|
||||
checker.diagnostics.push(diagnostic);
|
||||
}
|
||||
}
|
||||
if checker.enabled(Rule::InvalidArgumentName) {
|
||||
if let Some(diagnostic) = pep8_naming::rules::invalid_argument_name(
|
||||
&arg.arg,
|
||||
arg,
|
||||
&checker.settings.pep8_naming.ignore_names,
|
||||
) {
|
||||
checker.diagnostics.push(diagnostic);
|
||||
}
|
||||
}
|
||||
if checker.enabled(Rule::BuiltinArgumentShadowing) {
|
||||
flake8_builtins::rules::builtin_argument_shadowing(checker, arg);
|
||||
}
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
use ruff_python_ast::Arguments;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::codes::Rule;
|
||||
use crate::rules::{flake8_bugbear, flake8_pyi, ruff};
|
||||
|
||||
/// Run lint rules over a [`Arguments`] syntax node.
|
||||
pub(crate) fn arguments(arguments: &Arguments, checker: &mut Checker) {
|
||||
if checker.enabled(Rule::MutableArgumentDefault) {
|
||||
flake8_bugbear::rules::mutable_argument_default(checker, arguments);
|
||||
}
|
||||
if checker.enabled(Rule::FunctionCallInDefaultArgument) {
|
||||
flake8_bugbear::rules::function_call_in_argument_default(checker, arguments);
|
||||
}
|
||||
if checker.settings.rules.enabled(Rule::ImplicitOptional) {
|
||||
ruff::rules::implicit_optional(checker, arguments);
|
||||
}
|
||||
if checker.is_stub {
|
||||
if checker.enabled(Rule::TypedArgumentDefaultInStub) {
|
||||
flake8_pyi::rules::typed_argument_simple_defaults(checker, arguments);
|
||||
}
|
||||
if checker.enabled(Rule::ArgumentDefaultInStub) {
|
||||
flake8_pyi::rules::argument_simple_defaults(checker, arguments);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,84 +0,0 @@
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::codes::Rule;
|
||||
use crate::rules::{flake8_import_conventions, flake8_pyi, pyflakes, pylint};
|
||||
use ruff_diagnostics::{Diagnostic, Fix};
|
||||
|
||||
/// Run lint rules over the [`Binding`]s.
|
||||
pub(crate) fn bindings(checker: &mut Checker) {
|
||||
if !checker.any_enabled(&[
|
||||
Rule::InvalidAllFormat,
|
||||
Rule::InvalidAllObject,
|
||||
Rule::UnaliasedCollectionsAbcSetImport,
|
||||
Rule::UnconventionalImportAlias,
|
||||
Rule::UnusedPrivateTypeVar,
|
||||
Rule::UnusedVariable,
|
||||
Rule::UnusedPrivateProtocol,
|
||||
]) {
|
||||
return;
|
||||
}
|
||||
|
||||
for binding in checker.semantic.bindings.iter() {
|
||||
if checker.enabled(Rule::UnusedVariable) {
|
||||
if binding.kind.is_bound_exception() && !binding.is_used() {
|
||||
let mut diagnostic = Diagnostic::new(
|
||||
pyflakes::rules::UnusedVariable {
|
||||
name: binding.name(checker.locator).to_string(),
|
||||
},
|
||||
binding.range,
|
||||
);
|
||||
if checker.patch(Rule::UnusedVariable) {
|
||||
diagnostic.try_set_fix(|| {
|
||||
pyflakes::fixes::remove_exception_handler_assignment(
|
||||
binding,
|
||||
checker.locator,
|
||||
)
|
||||
.map(Fix::automatic)
|
||||
});
|
||||
}
|
||||
checker.diagnostics.push(diagnostic);
|
||||
}
|
||||
}
|
||||
if checker.enabled(Rule::InvalidAllFormat) {
|
||||
if let Some(diagnostic) = pylint::rules::invalid_all_format(binding) {
|
||||
checker.diagnostics.push(diagnostic);
|
||||
}
|
||||
}
|
||||
if checker.enabled(Rule::InvalidAllObject) {
|
||||
if let Some(diagnostic) = pylint::rules::invalid_all_object(binding) {
|
||||
checker.diagnostics.push(diagnostic);
|
||||
}
|
||||
}
|
||||
if checker.enabled(Rule::UnconventionalImportAlias) {
|
||||
if let Some(diagnostic) = flake8_import_conventions::rules::unconventional_import_alias(
|
||||
checker,
|
||||
binding,
|
||||
&checker.settings.flake8_import_conventions.aliases,
|
||||
) {
|
||||
checker.diagnostics.push(diagnostic);
|
||||
}
|
||||
}
|
||||
if checker.is_stub {
|
||||
if checker.enabled(Rule::UnaliasedCollectionsAbcSetImport) {
|
||||
if let Some(diagnostic) =
|
||||
flake8_pyi::rules::unaliased_collections_abc_set_import(checker, binding)
|
||||
{
|
||||
checker.diagnostics.push(diagnostic);
|
||||
}
|
||||
}
|
||||
if checker.enabled(Rule::UnusedPrivateTypeVar) {
|
||||
if let Some(diagnostic) =
|
||||
flake8_pyi::rules::unused_private_type_var(checker, binding)
|
||||
{
|
||||
checker.diagnostics.push(diagnostic);
|
||||
}
|
||||
}
|
||||
if checker.enabled(Rule::UnusedPrivateProtocol) {
|
||||
if let Some(diagnostic) =
|
||||
flake8_pyi::rules::unused_private_protocol(checker, binding)
|
||||
{
|
||||
checker.diagnostics.push(diagnostic);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
use ruff_python_ast::Comprehension;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::codes::Rule;
|
||||
use crate::rules::flake8_simplify;
|
||||
|
||||
/// Run lint rules over a [`Comprehension`] syntax nodes.
|
||||
pub(crate) fn comprehension(comprehension: &Comprehension, checker: &mut Checker) {
|
||||
if checker.enabled(Rule::InDictKeys) {
|
||||
flake8_simplify::rules::key_in_dict_for(
|
||||
checker,
|
||||
&comprehension.target,
|
||||
&comprehension.iter,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
use ruff_python_ast::{self as ast, Stmt};
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::codes::Rule;
|
||||
use crate::rules::{flake8_bugbear, perflint};
|
||||
|
||||
/// Run lint rules over all deferred for-loops in the [`SemanticModel`].
|
||||
pub(crate) fn deferred_for_loops(checker: &mut Checker) {
|
||||
while !checker.deferred.for_loops.is_empty() {
|
||||
let for_loops = std::mem::take(&mut checker.deferred.for_loops);
|
||||
for snapshot in for_loops {
|
||||
checker.semantic.restore(snapshot);
|
||||
|
||||
if let Stmt::For(ast::StmtFor {
|
||||
target, iter, body, ..
|
||||
})
|
||||
| Stmt::AsyncFor(ast::StmtAsyncFor {
|
||||
target, iter, body, ..
|
||||
}) = &checker.semantic.stmt()
|
||||
{
|
||||
if checker.enabled(Rule::UnusedLoopControlVariable) {
|
||||
flake8_bugbear::rules::unused_loop_control_variable(checker, target, body);
|
||||
}
|
||||
if checker.enabled(Rule::IncorrectDictIterator) {
|
||||
perflint::rules::incorrect_dict_iterator(checker, target, iter);
|
||||
}
|
||||
} else {
|
||||
unreachable!("Expected Expr::For | Expr::AsyncFor");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,287 +0,0 @@
|
||||
use ruff_diagnostics::Diagnostic;
|
||||
use ruff_python_ast::cast;
|
||||
use ruff_python_semantic::analyze::{branch_detection, visibility};
|
||||
use ruff_python_semantic::{Binding, BindingKind, ScopeKind};
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::codes::Rule;
|
||||
use crate::rules::{flake8_type_checking, flake8_unused_arguments, pyflakes, pylint};
|
||||
|
||||
/// Run lint rules over all deferred scopes in the [`SemanticModel`].
|
||||
pub(crate) fn deferred_scopes(checker: &mut Checker) {
|
||||
if !checker.any_enabled(&[
|
||||
Rule::GlobalVariableNotAssigned,
|
||||
Rule::ImportShadowedByLoopVar,
|
||||
Rule::RedefinedWhileUnused,
|
||||
Rule::RuntimeImportInTypeCheckingBlock,
|
||||
Rule::TypingOnlyFirstPartyImport,
|
||||
Rule::TypingOnlyStandardLibraryImport,
|
||||
Rule::TypingOnlyThirdPartyImport,
|
||||
Rule::UndefinedLocal,
|
||||
Rule::UnusedAnnotation,
|
||||
Rule::UnusedClassMethodArgument,
|
||||
Rule::UnusedFunctionArgument,
|
||||
Rule::UnusedImport,
|
||||
Rule::UnusedLambdaArgument,
|
||||
Rule::UnusedMethodArgument,
|
||||
Rule::UnusedStaticMethodArgument,
|
||||
Rule::UnusedVariable,
|
||||
]) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Identify any valid runtime imports. If a module is imported at runtime, and
|
||||
// used at runtime, then by default, we avoid flagging any other
|
||||
// imports from that model as typing-only.
|
||||
let enforce_typing_imports = !checker.is_stub
|
||||
&& checker.any_enabled(&[
|
||||
Rule::RuntimeImportInTypeCheckingBlock,
|
||||
Rule::TypingOnlyFirstPartyImport,
|
||||
Rule::TypingOnlyStandardLibraryImport,
|
||||
Rule::TypingOnlyThirdPartyImport,
|
||||
]);
|
||||
let runtime_imports: Vec<Vec<&Binding>> = if enforce_typing_imports {
|
||||
checker
|
||||
.semantic
|
||||
.scopes
|
||||
.iter()
|
||||
.map(|scope| {
|
||||
scope
|
||||
.binding_ids()
|
||||
.map(|binding_id| checker.semantic.binding(binding_id))
|
||||
.filter(|binding| {
|
||||
flake8_type_checking::helpers::is_valid_runtime_import(
|
||||
binding,
|
||||
&checker.semantic,
|
||||
)
|
||||
})
|
||||
.collect()
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
} else {
|
||||
vec![]
|
||||
};
|
||||
|
||||
let mut diagnostics: Vec<Diagnostic> = vec![];
|
||||
for scope_id in checker.deferred.scopes.iter().rev().copied() {
|
||||
let scope = &checker.semantic.scopes[scope_id];
|
||||
|
||||
if checker.enabled(Rule::UndefinedLocal) {
|
||||
pyflakes::rules::undefined_local(checker, scope_id, scope, &mut diagnostics);
|
||||
}
|
||||
|
||||
if checker.enabled(Rule::GlobalVariableNotAssigned) {
|
||||
for (name, binding_id) in scope.bindings() {
|
||||
let binding = checker.semantic.binding(binding_id);
|
||||
if binding.kind.is_global() {
|
||||
diagnostics.push(Diagnostic::new(
|
||||
pylint::rules::GlobalVariableNotAssigned {
|
||||
name: (*name).to_string(),
|
||||
},
|
||||
binding.range,
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if checker.enabled(Rule::ImportShadowedByLoopVar) {
|
||||
for (name, binding_id) in scope.bindings() {
|
||||
for shadow in checker.semantic.shadowed_bindings(scope_id, binding_id) {
|
||||
// If the shadowing binding isn't a loop variable, abort.
|
||||
let binding = &checker.semantic.bindings[shadow.binding_id()];
|
||||
if !binding.kind.is_loop_var() {
|
||||
continue;
|
||||
}
|
||||
|
||||
// If the shadowed binding isn't an import, abort.
|
||||
let shadowed = &checker.semantic.bindings[shadow.shadowed_id()];
|
||||
if !matches!(
|
||||
shadowed.kind,
|
||||
BindingKind::Import(..)
|
||||
| BindingKind::FromImport(..)
|
||||
| BindingKind::SubmoduleImport(..)
|
||||
| BindingKind::FutureImport
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// If the bindings are in different forks, abort.
|
||||
if shadowed.source.map_or(true, |left| {
|
||||
binding.source.map_or(true, |right| {
|
||||
branch_detection::different_forks(left, right, &checker.semantic.stmts)
|
||||
})
|
||||
}) {
|
||||
continue;
|
||||
}
|
||||
|
||||
#[allow(deprecated)]
|
||||
let line = checker.locator.compute_line_index(shadowed.range.start());
|
||||
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
pyflakes::rules::ImportShadowedByLoopVar {
|
||||
name: name.to_string(),
|
||||
line,
|
||||
},
|
||||
binding.range,
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if checker.enabled(Rule::RedefinedWhileUnused) {
|
||||
for (name, binding_id) in scope.bindings() {
|
||||
for shadow in checker.semantic.shadowed_bindings(scope_id, binding_id) {
|
||||
// If the shadowing binding is a loop variable, abort, to avoid overlap
|
||||
// with F402.
|
||||
let binding = &checker.semantic.bindings[shadow.binding_id()];
|
||||
if binding.kind.is_loop_var() {
|
||||
continue;
|
||||
}
|
||||
|
||||
// If the shadowed binding is used, abort.
|
||||
let shadowed = &checker.semantic.bindings[shadow.shadowed_id()];
|
||||
if shadowed.is_used() {
|
||||
continue;
|
||||
}
|
||||
|
||||
// If the shadowing binding isn't considered a "redefinition" of the
|
||||
// shadowed binding, abort.
|
||||
if !binding.redefines(shadowed) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if shadow.same_scope() {
|
||||
// If the symbol is a dummy variable, abort, unless the shadowed
|
||||
// binding is an import.
|
||||
if !matches!(
|
||||
shadowed.kind,
|
||||
BindingKind::Import(..)
|
||||
| BindingKind::FromImport(..)
|
||||
| BindingKind::SubmoduleImport(..)
|
||||
| BindingKind::FutureImport
|
||||
) && checker.settings.dummy_variable_rgx.is_match(name)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// If this is an overloaded function, abort.
|
||||
if shadowed.kind.is_function_definition()
|
||||
&& visibility::is_overload(
|
||||
cast::decorator_list(
|
||||
checker.semantic.stmts[shadowed.source.unwrap()],
|
||||
),
|
||||
&checker.semantic,
|
||||
)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
// Only enforce cross-scope shadowing for imports.
|
||||
if !matches!(
|
||||
shadowed.kind,
|
||||
BindingKind::Import(..)
|
||||
| BindingKind::FromImport(..)
|
||||
| BindingKind::SubmoduleImport(..)
|
||||
| BindingKind::FutureImport
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// If the bindings are in different forks, abort.
|
||||
if shadowed.source.map_or(true, |left| {
|
||||
binding.source.map_or(true, |right| {
|
||||
branch_detection::different_forks(left, right, &checker.semantic.stmts)
|
||||
})
|
||||
}) {
|
||||
continue;
|
||||
}
|
||||
|
||||
#[allow(deprecated)]
|
||||
let line = checker.locator.compute_line_index(shadowed.range.start());
|
||||
let mut diagnostic = Diagnostic::new(
|
||||
pyflakes::rules::RedefinedWhileUnused {
|
||||
name: (*name).to_string(),
|
||||
line,
|
||||
},
|
||||
binding.range,
|
||||
);
|
||||
if let Some(range) = binding.parent_range(&checker.semantic) {
|
||||
diagnostic.set_parent(range.start());
|
||||
}
|
||||
diagnostics.push(diagnostic);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if matches!(
|
||||
scope.kind,
|
||||
ScopeKind::Function(_) | ScopeKind::AsyncFunction(_) | ScopeKind::Lambda(_)
|
||||
) {
|
||||
if checker.enabled(Rule::UnusedVariable) {
|
||||
pyflakes::rules::unused_variable(checker, scope, &mut diagnostics);
|
||||
}
|
||||
|
||||
if checker.enabled(Rule::UnusedAnnotation) {
|
||||
pyflakes::rules::unused_annotation(checker, scope, &mut diagnostics);
|
||||
}
|
||||
|
||||
if !checker.is_stub {
|
||||
if checker.any_enabled(&[
|
||||
Rule::UnusedClassMethodArgument,
|
||||
Rule::UnusedFunctionArgument,
|
||||
Rule::UnusedLambdaArgument,
|
||||
Rule::UnusedMethodArgument,
|
||||
Rule::UnusedStaticMethodArgument,
|
||||
]) {
|
||||
flake8_unused_arguments::rules::unused_arguments(
|
||||
checker,
|
||||
scope,
|
||||
&mut diagnostics,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if matches!(
|
||||
scope.kind,
|
||||
ScopeKind::Function(_) | ScopeKind::AsyncFunction(_) | ScopeKind::Module
|
||||
) {
|
||||
if enforce_typing_imports {
|
||||
let runtime_imports: Vec<&Binding> = checker
|
||||
.semantic
|
||||
.scopes
|
||||
.ancestor_ids(scope_id)
|
||||
.flat_map(|scope_id| runtime_imports[scope_id.as_usize()].iter())
|
||||
.copied()
|
||||
.collect();
|
||||
|
||||
if checker.enabled(Rule::RuntimeImportInTypeCheckingBlock) {
|
||||
flake8_type_checking::rules::runtime_import_in_type_checking_block(
|
||||
checker,
|
||||
scope,
|
||||
&mut diagnostics,
|
||||
);
|
||||
}
|
||||
|
||||
if checker.any_enabled(&[
|
||||
Rule::TypingOnlyFirstPartyImport,
|
||||
Rule::TypingOnlyStandardLibraryImport,
|
||||
Rule::TypingOnlyThirdPartyImport,
|
||||
]) {
|
||||
flake8_type_checking::rules::typing_only_runtime_import(
|
||||
checker,
|
||||
scope,
|
||||
&runtime_imports,
|
||||
&mut diagnostics,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if checker.enabled(Rule::UnusedImport) {
|
||||
pyflakes::rules::unused_import(checker, scope, &mut diagnostics);
|
||||
}
|
||||
}
|
||||
}
|
||||
checker.diagnostics.extend(diagnostics);
|
||||
}
|
||||
@@ -1,291 +0,0 @@
|
||||
use ruff_python_ast::str::raw_contents_range;
|
||||
use ruff_python_ast::Ranged;
|
||||
use ruff_text_size::TextRange;
|
||||
|
||||
use ruff_python_semantic::{BindingKind, ContextualizedDefinition, Export};
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::codes::Rule;
|
||||
use crate::docstrings::Docstring;
|
||||
use crate::fs::relativize_path;
|
||||
use crate::rules::{flake8_annotations, flake8_pyi, pydocstyle};
|
||||
use crate::{docstrings, warn_user};
|
||||
|
||||
/// Run lint rules over all [`Definition`] nodes in the [`SemanticModel`].
|
||||
///
|
||||
/// This phase is expected to run after the AST has been traversed in its entirety; as such,
|
||||
/// it is expected that all [`Definition`] nodes have been visited by the time, and that this
|
||||
/// method will not recurse into any other nodes.
|
||||
pub(crate) fn definitions(checker: &mut Checker) {
|
||||
let enforce_annotations = checker.any_enabled(&[
|
||||
Rule::AnyType,
|
||||
Rule::MissingReturnTypeClassMethod,
|
||||
Rule::MissingReturnTypePrivateFunction,
|
||||
Rule::MissingReturnTypeSpecialMethod,
|
||||
Rule::MissingReturnTypeStaticMethod,
|
||||
Rule::MissingReturnTypeUndocumentedPublicFunction,
|
||||
Rule::MissingTypeArgs,
|
||||
Rule::MissingTypeCls,
|
||||
Rule::MissingTypeFunctionArgument,
|
||||
Rule::MissingTypeKwargs,
|
||||
Rule::MissingTypeSelf,
|
||||
]);
|
||||
let enforce_stubs = checker.is_stub
|
||||
&& checker.any_enabled(&[Rule::DocstringInStub, Rule::IterMethodReturnIterable]);
|
||||
let enforce_docstrings = checker.any_enabled(&[
|
||||
Rule::BlankLineAfterLastSection,
|
||||
Rule::BlankLineAfterSummary,
|
||||
Rule::BlankLineBeforeClass,
|
||||
Rule::BlankLinesBetweenHeaderAndContent,
|
||||
Rule::CapitalizeSectionName,
|
||||
Rule::DashedUnderlineAfterSection,
|
||||
Rule::DocstringStartsWithThis,
|
||||
Rule::EmptyDocstring,
|
||||
Rule::EmptyDocstringSection,
|
||||
Rule::EndsInPeriod,
|
||||
Rule::EndsInPunctuation,
|
||||
Rule::EscapeSequenceInDocstring,
|
||||
Rule::FirstLineCapitalized,
|
||||
Rule::FitsOnOneLine,
|
||||
Rule::IndentWithSpaces,
|
||||
Rule::MultiLineSummaryFirstLine,
|
||||
Rule::MultiLineSummarySecondLine,
|
||||
Rule::NewLineAfterLastParagraph,
|
||||
Rule::NewLineAfterSectionName,
|
||||
Rule::NoBlankLineAfterFunction,
|
||||
Rule::NoBlankLineAfterSection,
|
||||
Rule::NoBlankLineBeforeFunction,
|
||||
Rule::NoBlankLineBeforeSection,
|
||||
Rule::NoSignature,
|
||||
Rule::NonImperativeMood,
|
||||
Rule::OneBlankLineAfterClass,
|
||||
Rule::OneBlankLineBeforeClass,
|
||||
Rule::OverIndentation,
|
||||
Rule::OverloadWithDocstring,
|
||||
Rule::SectionNameEndsInColon,
|
||||
Rule::SectionNotOverIndented,
|
||||
Rule::SectionUnderlineAfterName,
|
||||
Rule::SectionUnderlineMatchesSectionLength,
|
||||
Rule::SectionUnderlineNotOverIndented,
|
||||
Rule::SurroundingWhitespace,
|
||||
Rule::TripleSingleQuotes,
|
||||
Rule::UnderIndentation,
|
||||
Rule::UndocumentedMagicMethod,
|
||||
Rule::UndocumentedParam,
|
||||
Rule::UndocumentedPublicClass,
|
||||
Rule::UndocumentedPublicFunction,
|
||||
Rule::UndocumentedPublicInit,
|
||||
Rule::UndocumentedPublicMethod,
|
||||
Rule::UndocumentedPublicModule,
|
||||
Rule::UndocumentedPublicNestedClass,
|
||||
Rule::UndocumentedPublicPackage,
|
||||
]);
|
||||
|
||||
if !enforce_annotations && !enforce_docstrings && !enforce_stubs {
|
||||
return;
|
||||
}
|
||||
|
||||
// Compute visibility of all definitions.
|
||||
let exports: Option<Vec<&str>> = {
|
||||
checker
|
||||
.semantic
|
||||
.global_scope()
|
||||
.get_all("__all__")
|
||||
.map(|binding_id| &checker.semantic.bindings[binding_id])
|
||||
.filter_map(|binding| match &binding.kind {
|
||||
BindingKind::Export(Export { names }) => Some(names.iter().copied()),
|
||||
_ => None,
|
||||
})
|
||||
.fold(None, |acc, names| {
|
||||
Some(acc.into_iter().flatten().chain(names).collect())
|
||||
})
|
||||
};
|
||||
|
||||
let definitions = std::mem::take(&mut checker.semantic.definitions);
|
||||
let mut overloaded_name: Option<String> = None;
|
||||
for ContextualizedDefinition {
|
||||
definition,
|
||||
visibility,
|
||||
} in definitions.resolve(exports.as_deref()).iter()
|
||||
{
|
||||
let docstring = docstrings::extraction::extract_docstring(definition);
|
||||
|
||||
// flake8-annotations
|
||||
if enforce_annotations {
|
||||
// TODO(charlie): This should be even stricter, in that an overload
|
||||
// implementation should come immediately after the overloaded
|
||||
// interfaces, without any AST nodes in between. Right now, we
|
||||
// only error when traversing definition boundaries (functions,
|
||||
// classes, etc.).
|
||||
if !overloaded_name.map_or(false, |overloaded_name| {
|
||||
flake8_annotations::helpers::is_overload_impl(
|
||||
definition,
|
||||
&overloaded_name,
|
||||
&checker.semantic,
|
||||
)
|
||||
}) {
|
||||
checker
|
||||
.diagnostics
|
||||
.extend(flake8_annotations::rules::definition(
|
||||
checker,
|
||||
definition,
|
||||
*visibility,
|
||||
));
|
||||
}
|
||||
overloaded_name =
|
||||
flake8_annotations::helpers::overloaded_name(definition, &checker.semantic);
|
||||
}
|
||||
|
||||
// flake8-pyi
|
||||
if enforce_stubs {
|
||||
if checker.enabled(Rule::DocstringInStub) {
|
||||
flake8_pyi::rules::docstring_in_stubs(checker, docstring);
|
||||
}
|
||||
if checker.enabled(Rule::IterMethodReturnIterable) {
|
||||
flake8_pyi::rules::iter_method_return_iterable(checker, definition);
|
||||
}
|
||||
}
|
||||
|
||||
// pydocstyle
|
||||
if enforce_docstrings {
|
||||
if pydocstyle::helpers::should_ignore_definition(
|
||||
definition,
|
||||
&checker.settings.pydocstyle.ignore_decorators,
|
||||
&checker.semantic,
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Extract a `Docstring` from a `Definition`.
|
||||
let Some(expr) = docstring else {
|
||||
pydocstyle::rules::not_missing(checker, definition, *visibility);
|
||||
continue;
|
||||
};
|
||||
|
||||
let contents = checker.locator.slice(expr.range());
|
||||
|
||||
let indentation = checker.locator.slice(TextRange::new(
|
||||
checker.locator.line_start(expr.start()),
|
||||
expr.start(),
|
||||
));
|
||||
|
||||
if pydocstyle::helpers::should_ignore_docstring(contents) {
|
||||
#[allow(deprecated)]
|
||||
let location = checker.locator.compute_source_location(expr.start());
|
||||
warn_user!(
|
||||
"Docstring at {}:{}:{} contains implicit string concatenation; ignoring...",
|
||||
relativize_path(checker.path),
|
||||
location.row,
|
||||
location.column
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
// SAFETY: Safe for docstrings that pass `should_ignore_docstring`.
|
||||
let body_range = raw_contents_range(contents).unwrap();
|
||||
let docstring = Docstring {
|
||||
definition,
|
||||
expr,
|
||||
contents,
|
||||
body_range,
|
||||
indentation,
|
||||
};
|
||||
|
||||
if !pydocstyle::rules::not_empty(checker, &docstring) {
|
||||
continue;
|
||||
}
|
||||
if checker.enabled(Rule::FitsOnOneLine) {
|
||||
pydocstyle::rules::one_liner(checker, &docstring);
|
||||
}
|
||||
if checker.any_enabled(&[
|
||||
Rule::NoBlankLineAfterFunction,
|
||||
Rule::NoBlankLineBeforeFunction,
|
||||
]) {
|
||||
pydocstyle::rules::blank_before_after_function(checker, &docstring);
|
||||
}
|
||||
if checker.any_enabled(&[
|
||||
Rule::BlankLineBeforeClass,
|
||||
Rule::OneBlankLineAfterClass,
|
||||
Rule::OneBlankLineBeforeClass,
|
||||
]) {
|
||||
pydocstyle::rules::blank_before_after_class(checker, &docstring);
|
||||
}
|
||||
if checker.enabled(Rule::BlankLineAfterSummary) {
|
||||
pydocstyle::rules::blank_after_summary(checker, &docstring);
|
||||
}
|
||||
if checker.any_enabled(&[
|
||||
Rule::IndentWithSpaces,
|
||||
Rule::OverIndentation,
|
||||
Rule::UnderIndentation,
|
||||
]) {
|
||||
pydocstyle::rules::indent(checker, &docstring);
|
||||
}
|
||||
if checker.enabled(Rule::NewLineAfterLastParagraph) {
|
||||
pydocstyle::rules::newline_after_last_paragraph(checker, &docstring);
|
||||
}
|
||||
if checker.enabled(Rule::SurroundingWhitespace) {
|
||||
pydocstyle::rules::no_surrounding_whitespace(checker, &docstring);
|
||||
}
|
||||
if checker.any_enabled(&[
|
||||
Rule::MultiLineSummaryFirstLine,
|
||||
Rule::MultiLineSummarySecondLine,
|
||||
]) {
|
||||
pydocstyle::rules::multi_line_summary_start(checker, &docstring);
|
||||
}
|
||||
if checker.enabled(Rule::TripleSingleQuotes) {
|
||||
pydocstyle::rules::triple_quotes(checker, &docstring);
|
||||
}
|
||||
if checker.enabled(Rule::EscapeSequenceInDocstring) {
|
||||
pydocstyle::rules::backslashes(checker, &docstring);
|
||||
}
|
||||
if checker.enabled(Rule::EndsInPeriod) {
|
||||
pydocstyle::rules::ends_with_period(checker, &docstring);
|
||||
}
|
||||
if checker.enabled(Rule::NonImperativeMood) {
|
||||
pydocstyle::rules::non_imperative_mood(
|
||||
checker,
|
||||
&docstring,
|
||||
&checker.settings.pydocstyle.property_decorators,
|
||||
);
|
||||
}
|
||||
if checker.enabled(Rule::NoSignature) {
|
||||
pydocstyle::rules::no_signature(checker, &docstring);
|
||||
}
|
||||
if checker.enabled(Rule::FirstLineCapitalized) {
|
||||
pydocstyle::rules::capitalized(checker, &docstring);
|
||||
}
|
||||
if checker.enabled(Rule::DocstringStartsWithThis) {
|
||||
pydocstyle::rules::starts_with_this(checker, &docstring);
|
||||
}
|
||||
if checker.enabled(Rule::EndsInPunctuation) {
|
||||
pydocstyle::rules::ends_with_punctuation(checker, &docstring);
|
||||
}
|
||||
if checker.enabled(Rule::OverloadWithDocstring) {
|
||||
pydocstyle::rules::if_needed(checker, &docstring);
|
||||
}
|
||||
if checker.any_enabled(&[
|
||||
Rule::BlankLineAfterLastSection,
|
||||
Rule::BlankLinesBetweenHeaderAndContent,
|
||||
Rule::CapitalizeSectionName,
|
||||
Rule::DashedUnderlineAfterSection,
|
||||
Rule::EmptyDocstringSection,
|
||||
Rule::MultiLineSummaryFirstLine,
|
||||
Rule::NewLineAfterSectionName,
|
||||
Rule::NoBlankLineAfterSection,
|
||||
Rule::NoBlankLineBeforeSection,
|
||||
Rule::SectionNameEndsInColon,
|
||||
Rule::SectionNotOverIndented,
|
||||
Rule::SectionUnderlineAfterName,
|
||||
Rule::SectionUnderlineMatchesSectionLength,
|
||||
Rule::SectionUnderlineNotOverIndented,
|
||||
Rule::UndocumentedParam,
|
||||
]) {
|
||||
pydocstyle::rules::sections(
|
||||
checker,
|
||||
&docstring,
|
||||
checker.settings.pydocstyle.convention.as_ref(),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,88 +0,0 @@
|
||||
use ruff_python_ast::{self as ast, ExceptHandler, Ranged};
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::registry::Rule;
|
||||
use crate::rules::{
|
||||
flake8_bandit, flake8_blind_except, flake8_bugbear, flake8_builtins, pycodestyle, pylint,
|
||||
tryceratops,
|
||||
};
|
||||
|
||||
/// Run lint rules over an [`ExceptHandler`] syntax node.
|
||||
pub(crate) fn except_handler(except_handler: &ExceptHandler, checker: &mut Checker) {
|
||||
match except_handler {
|
||||
ExceptHandler::ExceptHandler(ast::ExceptHandlerExceptHandler {
|
||||
type_,
|
||||
name,
|
||||
body,
|
||||
range: _,
|
||||
}) => {
|
||||
if checker.enabled(Rule::BareExcept) {
|
||||
if let Some(diagnostic) = pycodestyle::rules::bare_except(
|
||||
type_.as_deref(),
|
||||
body,
|
||||
except_handler,
|
||||
checker.locator,
|
||||
) {
|
||||
checker.diagnostics.push(diagnostic);
|
||||
}
|
||||
}
|
||||
if checker.enabled(Rule::RaiseWithoutFromInsideExcept) {
|
||||
flake8_bugbear::rules::raise_without_from_inside_except(
|
||||
checker,
|
||||
name.as_deref(),
|
||||
body,
|
||||
);
|
||||
}
|
||||
if checker.enabled(Rule::BlindExcept) {
|
||||
flake8_blind_except::rules::blind_except(
|
||||
checker,
|
||||
type_.as_deref(),
|
||||
name.as_deref(),
|
||||
body,
|
||||
);
|
||||
}
|
||||
if checker.enabled(Rule::TryExceptPass) {
|
||||
flake8_bandit::rules::try_except_pass(
|
||||
checker,
|
||||
except_handler,
|
||||
type_.as_deref(),
|
||||
body,
|
||||
checker.settings.flake8_bandit.check_typed_exception,
|
||||
);
|
||||
}
|
||||
if checker.enabled(Rule::TryExceptContinue) {
|
||||
flake8_bandit::rules::try_except_continue(
|
||||
checker,
|
||||
except_handler,
|
||||
type_.as_deref(),
|
||||
body,
|
||||
checker.settings.flake8_bandit.check_typed_exception,
|
||||
);
|
||||
}
|
||||
if checker.enabled(Rule::ExceptWithEmptyTuple) {
|
||||
flake8_bugbear::rules::except_with_empty_tuple(checker, except_handler);
|
||||
}
|
||||
if checker.enabled(Rule::ExceptWithNonExceptionClasses) {
|
||||
flake8_bugbear::rules::except_with_non_exception_classes(checker, except_handler);
|
||||
}
|
||||
if checker.enabled(Rule::ReraiseNoCause) {
|
||||
tryceratops::rules::reraise_no_cause(checker, body);
|
||||
}
|
||||
if checker.enabled(Rule::BinaryOpException) {
|
||||
pylint::rules::binary_op_exception(checker, except_handler);
|
||||
}
|
||||
if let Some(name) = name {
|
||||
if checker.enabled(Rule::AmbiguousVariableName) {
|
||||
if let Some(diagnostic) =
|
||||
pycodestyle::rules::ambiguous_variable_name(name.as_str(), name.range())
|
||||
{
|
||||
checker.diagnostics.push(diagnostic);
|
||||
}
|
||||
}
|
||||
if checker.enabled(Rule::BuiltinVariableShadowing) {
|
||||
flake8_builtins::rules::builtin_variable_shadowing(checker, name, name.range());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,27 +0,0 @@
|
||||
pub(super) use argument::argument;
|
||||
pub(super) use arguments::arguments;
|
||||
pub(super) use bindings::bindings;
|
||||
pub(super) use comprehension::comprehension;
|
||||
pub(super) use deferred_for_loops::deferred_for_loops;
|
||||
pub(super) use deferred_scopes::deferred_scopes;
|
||||
pub(super) use definitions::definitions;
|
||||
pub(super) use except_handler::except_handler;
|
||||
pub(super) use expression::expression;
|
||||
pub(super) use module::module;
|
||||
pub(super) use statement::statement;
|
||||
pub(super) use suite::suite;
|
||||
pub(super) use unresolved_references::unresolved_references;
|
||||
|
||||
mod argument;
|
||||
mod arguments;
|
||||
mod bindings;
|
||||
mod comprehension;
|
||||
mod deferred_for_loops;
|
||||
mod deferred_scopes;
|
||||
mod definitions;
|
||||
mod except_handler;
|
||||
mod expression;
|
||||
mod module;
|
||||
mod statement;
|
||||
mod suite;
|
||||
mod unresolved_references;
|
||||
@@ -1,12 +0,0 @@
|
||||
use ruff_python_ast::Suite;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::codes::Rule;
|
||||
use crate::rules::flake8_bugbear;
|
||||
|
||||
/// Run lint rules over a module.
|
||||
pub(crate) fn module(suite: &Suite, checker: &mut Checker) {
|
||||
if checker.enabled(Rule::FStringDocstring) {
|
||||
flake8_bugbear::rules::f_string_docstring(checker, suite);
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,12 +0,0 @@
|
||||
use ruff_python_ast::Stmt;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::codes::Rule;
|
||||
use crate::rules::flake8_pie;
|
||||
|
||||
/// Run lint rules over a suite of [`Stmt`] syntax nodes.
|
||||
pub(crate) fn suite(suite: &[Stmt], checker: &mut Checker) {
|
||||
if checker.enabled(Rule::UnnecessaryPass) {
|
||||
flake8_pie::rules::no_unnecessary_pass(checker, suite);
|
||||
}
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
use ruff_diagnostics::Diagnostic;
|
||||
use ruff_python_semantic::Exceptions;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::codes::Rule;
|
||||
use crate::rules::pyflakes;
|
||||
|
||||
/// Run lint rules over all [`UnresolvedReference`] entities in the [`SemanticModel`].
|
||||
pub(crate) fn unresolved_references(checker: &mut Checker) {
|
||||
if !checker.any_enabled(&[Rule::UndefinedLocalWithImportStarUsage, Rule::UndefinedName]) {
|
||||
return;
|
||||
}
|
||||
|
||||
for reference in checker.semantic.unresolved_references() {
|
||||
if reference.is_wildcard_import() {
|
||||
if checker.enabled(Rule::UndefinedLocalWithImportStarUsage) {
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
pyflakes::rules::UndefinedLocalWithImportStarUsage {
|
||||
name: reference.name(checker.locator).to_string(),
|
||||
},
|
||||
reference.range(),
|
||||
));
|
||||
}
|
||||
} else {
|
||||
if checker.enabled(Rule::UndefinedName) {
|
||||
// Avoid flagging if `NameError` is handled.
|
||||
if reference.exceptions().contains(Exceptions::NAME_ERROR) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Allow __path__.
|
||||
if checker.path.ends_with("__init__.py") {
|
||||
if reference.name(checker.locator) == "__path__" {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
pyflakes::rules::UndefinedName {
|
||||
name: reference.name(checker.locator).to_string(),
|
||||
},
|
||||
reference.range(),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
use ruff_python_ast::Expr;
|
||||
use ruff_text_size::TextRange;
|
||||
use rustpython_parser::ast::Expr;
|
||||
|
||||
use ruff_python_semantic::{ScopeId, Snapshot};
|
||||
|
||||
@@ -14,4 +14,5 @@ pub(crate) struct Deferred<'a> {
|
||||
pub(crate) functions: Vec<Snapshot>,
|
||||
pub(crate) lambdas: Vec<(&'a Expr, Snapshot)>,
|
||||
pub(crate) for_loops: Vec<Snapshot>,
|
||||
pub(crate) assignments: Vec<Snapshot>,
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -2,16 +2,14 @@
|
||||
use std::borrow::Cow;
|
||||
use std::path::Path;
|
||||
|
||||
use ruff_python_ast::{self as ast, Ranged, Stmt, Suite};
|
||||
use rustpython_parser::ast::{self, Ranged, Stmt, Suite};
|
||||
|
||||
use ruff_diagnostics::Diagnostic;
|
||||
use ruff_python_ast::helpers::to_module_path;
|
||||
use ruff_python_ast::imports::{ImportMap, ModuleImport};
|
||||
use ruff_python_ast::source_code::{Indexer, Locator, Stylist};
|
||||
use ruff_python_ast::statement_visitor::StatementVisitor;
|
||||
use ruff_python_codegen::Stylist;
|
||||
use ruff_python_index::Indexer;
|
||||
use ruff_python_stdlib::path::is_python_stub_file;
|
||||
use ruff_source_file::Locator;
|
||||
|
||||
use crate::directives::IsortDirectives;
|
||||
use crate::registry::Rule;
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
use ruff_python_parser::lexer::LexResult;
|
||||
use ruff_text_size::TextRange;
|
||||
use rustpython_parser::lexer::LexResult;
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, DiagnosticKind};
|
||||
use ruff_python_codegen::Stylist;
|
||||
use ruff_python_parser::TokenKind;
|
||||
use ruff_source_file::Locator;
|
||||
use ruff_python_ast::source_code::{Locator, Stylist};
|
||||
use ruff_python_ast::token_kind::TokenKind;
|
||||
|
||||
use crate::registry::{AsRule, Rule};
|
||||
use crate::rules::pycodestyle::rules::logical_lines::{
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user