Compare commits

...

22 Commits

Author SHA1 Message Date
Charlie Marsh
e3cc918b93 Bump version to 0.0.222 2023-01-14 23:34:53 -05:00
Charlie Marsh
d864477876 Turn doc references into links (#1878) 2023-01-14 23:27:45 -05:00
Charlie Marsh
e1ced89624 Document breaking --max-complexity change 2023-01-14 23:22:38 -05:00
Martin Fischer
4470d7ba04 Make the CI check for broken links in the Rust docs (#1883) 2023-01-14 23:18:17 -05:00
Harutaka Kawamura
2a1601749f Fix range of SIM201, 202, and 208 (#1880)
Before

```
resources/test/fixtures/flake8_simplify/SIM208.py:1:13: SIM208 Use `a` instead of `not (not a)`
  |
1 | if not (not a):  # SIM208
  |             ^ SIM208
  |
  = help: Replace with `a`

resources/test/fixtures/flake8_simplify/SIM208.py:4:14: SIM208 Use `a == b` instead of `not (not a == b)`
  |
4 | if not (not (a == b)):  # SIM208
  |              ^^^^^^ SIM208
  |
  = help: Replace with `a == b`
```

After

```
resources/test/fixtures/flake8_simplify/SIM208.py:1:4: SIM208 Use `a` instead of `not (not a)`
  |
1 | if not (not a):  # SIM208
  |    ^^^^^^^^^^^ SIM208
  |
  = help: Replace with `a`

resources/test/fixtures/flake8_simplify/SIM208.py:4:4: SIM208 Use `a == b` instead of `not (not a == b)`
  |
4 | if not (not (a == b)):  # SIM208
  |    ^^^^^^^^^^^^^^^^^^ SIM208
  |
  = help: Replace with `a == b`
```
2023-01-14 21:17:32 -05:00
Charlie Marsh
a01edad1c4 Remove --max-complexity from the CLI (#1877) 2023-01-14 18:27:23 -05:00
Martin Fischer
a81ac6705d Make ruff::source_code::{Generator, Locator, Stylist} private 2023-01-14 18:23:59 -05:00
Martin Fischer
d77675f30d Make ruff::{ast, autofix, directives, rustpython_helpers} private 2023-01-14 18:23:59 -05:00
Martin Fischer
fe7658199d Make ruff::violations private 2023-01-14 18:23:59 -05:00
Martin Fischer
cfa25ea4b0 Make ruff::rules private 2023-01-14 18:23:59 -05:00
Martin Fischer
c7f0f3b237 Regenerate insta snapshots 2023-01-14 11:48:02 -05:00
Martin Fischer
3b36030461 Introduce ruff::rules module
Resolves #1547.
2023-01-14 11:48:02 -05:00
Charlie Marsh
812df77246 Add Dagster and SnowCLI 2023-01-14 10:45:16 -05:00
Martin Fischer
69b356e9b9 Add top-level doc comments for crates
Test by running:

    cargo doc --no-deps --all --open
2023-01-14 10:11:30 -05:00
Martin Fischer
033d7d7e91 Disable doc generation for the ruff_cli binary 2023-01-14 10:11:30 -05:00
Martin Fischer
a181ca7a3d Reduce the API of ruff_cli to ruff_cli::help() 2023-01-14 10:11:30 -05:00
Martin Fischer
92124001d5 Turn ruff_dev into a bin-only crate 2023-01-14 10:11:30 -05:00
Martin Fischer
06b389c5bc Turn flake8_to_ruff into a bin-only crate 2023-01-14 10:11:30 -05:00
Thomas MK
9dc66b5a65 Split up the table corresponding to the pylint rules (#1868)
This makes it easier to see which rules you're enabling when selecting
one of the pylint codes (like `PLC`). This also makes it clearer what
those abbreviations stand for. When I first saw the pylint section, I
was very confused by that, so other might be as well.

See it rendered here:
https://github.com/thomkeh/ruff/blob/patch-1/README.md#pylint-plc-ple-plr-plw
2023-01-14 08:07:02 -05:00
Ran Benita
3447dd3615 Bump RustPython (#1836)
This bumps RustPython so we can use the new `NonLogicalNewline` token.
A couple of rules needed a fix due to the new token. There might be more
that are not caught by tests (anything working with tokens directly with
lookaheads), I hope not.
2023-01-14 08:03:27 -05:00
Harutaka Kawamura
42cb106377 Improve SIM117 (#1867)
This PR makes the following changes to improve `SIM117`:

- Avoid emitting `SIM117` multiple times within the same `with`
statement:
- Adjust the error range.  


## Example

```python
with A() as a:  # SIM117
    with B() as b:
        with C() as c:
            print("hello")
```

### Current

```
resources/test/fixtures/flake8_simplify/SIM117.py:5:1: SIM117 Use a single `with` statement with multiple contexts instead of nested `with` statements
  |
5 | / with A() as a:  # SIM117
6 | |     with B() as b:
7 | |         with C() as c:
8 | |             print("hello")
  | |__________________________^ SIM117
  |

resources/test/fixtures/flake8_simplify/SIM117.py:6:5: SIM117 Use a single `with` statement with multiple contexts instead of nested `with` statements
  |
6 |       with B() as b:
  |  _____^
7 | |         with C() as c:
8 | |             print("hello")
  | |__________________________^ SIM117
  |
```

### Improved

```
resources/test/fixtures/flake8_simplify/SIM117.py:5:1: SIM117 Use a single `with` statement with multiple contexts instead of nested `with` statements
  |
5 | / with A() as a:  # SIM117
6 | |     with B() as b:
7 | |         with C() as c:
  | |______________________^ SIM117
  |
```

Signed-off-by: harupy <hkawamura0130@gmail.com>
2023-01-14 07:59:24 -05:00
Charlie Marsh
027382f891 Add support for namespace packages (#1859)
Closes #1817.
2023-01-14 07:31:57 -05:00
883 changed files with 2037 additions and 1774 deletions

View File

@@ -80,6 +80,9 @@ jobs:
cargo insta test --all --delete-unreferenced-snapshots
git diff --exit-code
- run: cargo test --package ruff_cli --test black_compatibility_test -- --ignored
# Check for broken links in the documentation.
# Setting RUSTDOCFLAGS because `cargo doc --check` isn't yet implemented (https://github.com/rust-lang/cargo/issues/10025).
- run: RUSTDOCFLAGS="-D warnings" cargo doc --all --no-deps
# TODO(charlie): Re-enable the `wasm-pack` tests.
# See: https://github.com/charliermarsh/ruff/issues/1425

View File

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

View File

@@ -1,5 +1,20 @@
# Breaking Changes
## 0.0.222
### `--max-complexity` has been removed from the CLI ([#1877](https://github.com/charliermarsh/ruff/pull/1877))
The McCabe plugin's `--max-complexity` setting has been removed from the CLI, for consistency with
the treatment of other, similar settings.
To set the maximum complexity, use the `max-complexity` property in your `pyproject.toml` file,
like so:
```toml
[tool.ruff.mccabe]
max-complexity = 10
```
## 0.0.181
### Files excluded by `.gitignore` are now ignored ([#1234](https://github.com/charliermarsh/ruff/pull/1234))

69
Cargo.lock generated
View File

@@ -735,7 +735,7 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
[[package]]
name = "flake8-to-ruff"
version = "0.0.221-dev.0"
version = "0.0.222-dev.0"
dependencies = [
"anyhow",
"clap 4.0.32",
@@ -1364,6 +1364,27 @@ dependencies = [
"libc",
]
[[package]]
name = "num_enum"
version = "0.5.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf5395665662ef45796a4ff5486c5d41d29e0c09640af4c5f17fd94ee2c119c9"
dependencies = [
"num_enum_derive",
]
[[package]]
name = "num_enum_derive"
version = "0.5.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b0498641e53dd6ac1a4f22547548caa6864cc4933784319cd1775271c5a46ce"
dependencies = [
"proc-macro-crate",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "once_cell"
version = "1.17.0"
@@ -1621,6 +1642,17 @@ dependencies = [
"termtree",
]
[[package]]
name = "proc-macro-crate"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eda0fc3b0fb7c975631757e14d9049da17374063edb6ebbcbc54d880d4fe94e9"
dependencies = [
"once_cell",
"thiserror",
"toml",
]
[[package]]
name = "proc-macro-error"
version = "1.0.4"
@@ -1874,7 +1906,7 @@ dependencies = [
[[package]]
name = "ruff"
version = "0.0.221"
version = "0.0.222"
dependencies = [
"anyhow",
"bitflags",
@@ -1926,7 +1958,7 @@ dependencies = [
[[package]]
name = "ruff_cli"
version = "0.0.221"
version = "0.0.222"
dependencies = [
"annotate-snippets 0.9.1",
"anyhow",
@@ -1963,7 +1995,7 @@ dependencies = [
[[package]]
name = "ruff_dev"
version = "0.0.221"
version = "0.0.222"
dependencies = [
"anyhow",
"clap 4.0.32",
@@ -1984,7 +2016,7 @@ dependencies = [
[[package]]
name = "ruff_macros"
version = "0.0.221"
version = "0.0.222"
dependencies = [
"once_cell",
"proc-macro2",
@@ -2027,8 +2059,8 @@ dependencies = [
[[package]]
name = "rustpython-ast"
version = "0.1.0"
source = "git+https://github.com/RustPython/RustPython.git?rev=d532160333ffeb6dbeca2c2728c2391cd1e53b7f#d532160333ffeb6dbeca2c2728c2391cd1e53b7f"
version = "0.2.0"
source = "git+https://github.com/RustPython/RustPython.git?rev=acbc517b55406c76da83d7b2711941d8d3f65b87#acbc517b55406c76da83d7b2711941d8d3f65b87"
dependencies = [
"num-bigint",
"rustpython-common",
@@ -2037,8 +2069,8 @@ dependencies = [
[[package]]
name = "rustpython-common"
version = "0.0.0"
source = "git+https://github.com/RustPython/RustPython.git?rev=d532160333ffeb6dbeca2c2728c2391cd1e53b7f#d532160333ffeb6dbeca2c2728c2391cd1e53b7f"
version = "0.2.0"
source = "git+https://github.com/RustPython/RustPython.git?rev=acbc517b55406c76da83d7b2711941d8d3f65b87#acbc517b55406c76da83d7b2711941d8d3f65b87"
dependencies = [
"ascii",
"bitflags",
@@ -2062,8 +2094,8 @@ dependencies = [
[[package]]
name = "rustpython-compiler-core"
version = "0.1.2"
source = "git+https://github.com/RustPython/RustPython.git?rev=d532160333ffeb6dbeca2c2728c2391cd1e53b7f#d532160333ffeb6dbeca2c2728c2391cd1e53b7f"
version = "0.2.0"
source = "git+https://github.com/RustPython/RustPython.git?rev=acbc517b55406c76da83d7b2711941d8d3f65b87#acbc517b55406c76da83d7b2711941d8d3f65b87"
dependencies = [
"bincode",
"bitflags",
@@ -2072,15 +2104,15 @@ dependencies = [
"lz4_flex",
"num-bigint",
"num-complex",
"num_enum",
"serde",
"static_assertions",
"thiserror",
]
[[package]]
name = "rustpython-parser"
version = "0.1.2"
source = "git+https://github.com/RustPython/RustPython.git?rev=d532160333ffeb6dbeca2c2728c2391cd1e53b7f#d532160333ffeb6dbeca2c2728c2391cd1e53b7f"
version = "0.2.0"
source = "git+https://github.com/RustPython/RustPython.git?rev=acbc517b55406c76da83d7b2711941d8d3f65b87#acbc517b55406c76da83d7b2711941d8d3f65b87"
dependencies = [
"ahash",
"anyhow",
@@ -2518,6 +2550,15 @@ dependencies = [
"regex",
]
[[package]]
name = "toml"
version = "0.5.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1333c76748e868a4d9d1017b5ab53171dfd095f70c712fdb4653a406547f598f"
dependencies = [
"serde",
]
[[package]]
name = "toml_datetime"
version = "0.5.0"

View File

@@ -8,7 +8,7 @@ default-members = [".", "ruff_cli"]
[package]
name = "ruff"
version = "0.0.221"
version = "0.0.222"
authors = ["Charlie Marsh <charlie.r.marsh@gmail.com>"]
edition = "2021"
rust-version = "1.65.0"
@@ -46,11 +46,11 @@ once_cell = { version = "1.16.0" }
path-absolutize = { version = "3.0.14", features = ["once_cell_cache", "use_unix_paths_on_wasm"] }
regex = { version = "1.6.0" }
ropey = { version = "1.5.0", features = ["cr_lines", "simd"], default-features = false }
ruff_macros = { version = "0.0.221", path = "ruff_macros" }
ruff_macros = { version = "0.0.222", path = "ruff_macros" }
rustc-hash = { version = "1.1.0" }
rustpython-ast = { features = ["unparse"], git = "https://github.com/RustPython/RustPython.git", rev = "d532160333ffeb6dbeca2c2728c2391cd1e53b7f" }
rustpython-common = { git = "https://github.com/RustPython/RustPython.git", rev = "d532160333ffeb6dbeca2c2728c2391cd1e53b7f" }
rustpython-parser = { features = ["lalrpop"], git = "https://github.com/RustPython/RustPython.git", rev = "d532160333ffeb6dbeca2c2728c2391cd1e53b7f" }
rustpython-ast = { features = ["unparse"], git = "https://github.com/RustPython/RustPython.git", rev = "acbc517b55406c76da83d7b2711941d8d3f65b87" }
rustpython-common = { git = "https://github.com/RustPython/RustPython.git", rev = "acbc517b55406c76da83d7b2711941d8d3f65b87" }
rustpython-parser = { features = ["lalrpop"], git = "https://github.com/RustPython/RustPython.git", rev = "acbc517b55406c76da83d7b2711941d8d3f65b87" }
schemars = { version = "0.8.11" }
semver = { version = "1.0.16" }
serde = { version = "1.0.147", features = ["derive"] }

View File

@@ -51,16 +51,18 @@ Ruff is extremely actively developed and used in major open-source projects like
- [Apache Airflow](https://github.com/apache/airflow)
- [Bokeh](https://github.com/bokeh/bokeh)
- [Zulip](https://github.com/zulip/zulip)
- [Dagster](https://github.com/dagster-io/dagster)
- [Pydantic](https://github.com/pydantic/pydantic)
- [Sphinx](https://github.com/sphinx-doc/sphinx)
- [Hatch](https://github.com/pypa/hatch)
- [Jupyter](https://github.com/jupyter-server/jupyter_server)
- [Synapse](https://github.com/matrix-org/synapse)
- [Synapse (Matrix)](https://github.com/matrix-org/synapse)
- [Saleor](https://github.com/saleor/saleor)
- [Polars](https://github.com/pola-rs/polars)
- [Ibis](https://github.com/ibis-project/ibis)
- [OpenBB](https://github.com/OpenBB-finance/OpenBBTerminal)
- [`pyca/cryptography`](https://github.com/pyca/cryptography)
- [Cryptography (PyCA)](https://github.com/pyca/cryptography)
- [SnowCLI (Snowflake)](https://github.com/Snowflake-Labs/snowcli)
Read the [launch blog post](https://notes.crmarsh.com/python-tooling-could-be-much-much-faster).
@@ -182,7 +184,7 @@ Ruff also works with [pre-commit](https://pre-commit.com):
```yaml
- repo: https://github.com/charliermarsh/ruff-pre-commit
# Ruff version.
rev: 'v0.0.221'
rev: 'v0.0.222'
hooks:
- id: ruff
# Respect `exclude` and `extend-exclude` settings.
@@ -383,8 +385,6 @@ Options:
The minimum Python version that should be supported
--line-length <LINE_LENGTH>
Set the line-length for length-associated rules and automatic formatting
--max-complexity <MAX_COMPLEXITY>
Maximum McCabe complexity allowed for a given function
--add-noqa
Enable automatic additions of `noqa` directives to failing lines
--clean
@@ -581,6 +581,7 @@ For more, see [Pyflakes](https://pypi.org/project/pyflakes/2.5.0/) on PyPI.
For more, see [pycodestyle](https://pypi.org/project/pycodestyle/2.9.1/) on PyPI.
#### Error (E)
| Code | Name | Message | Fix |
| ---- | ---- | ------- | --- |
| E401 | MultipleImportsOnOneLine | Multiple imports on one line | |
@@ -598,6 +599,10 @@ For more, see [pycodestyle](https://pypi.org/project/pycodestyle/2.9.1/) on PyPI
| E743 | AmbiguousFunctionName | Ambiguous function name: `...` | |
| E902 | IOError | IOError: `...` | |
| E999 | SyntaxError | SyntaxError: `...` | |
#### Warning (W)
| Code | Name | Message | Fix |
| ---- | ---- | ------- | --- |
| W292 | NoNewLineAtEndOfFile | No newline at end of file | 🛠 |
| W505 | DocLineTooLong | Doc line too long (89 > 88 characters) | |
| W605 | InvalidEscapeSequence | Invalid escape sequence: '\c' | 🛠 |
@@ -979,7 +984,6 @@ For more, see [flake8-simplify](https://pypi.org/project/flake8-simplify/0.19.3/
| Code | Name | Message | Fix |
| ---- | ---- | ------- | --- |
| SIM115 | OpenFileWithContextHandler | Use context handler for opening files | |
| SIM101 | DuplicateIsinstanceCall | Multiple `isinstance` calls for `...`, merge into a single call | 🛠 |
| SIM102 | NestedIfStatements | Use a single `if` statement instead of nested `if` statements | |
| SIM103 | ReturnBoolConditionDirectly | Return the condition `...` directly | 🛠 |
@@ -990,6 +994,7 @@ For more, see [flake8-simplify](https://pypi.org/project/flake8-simplify/0.19.3/
| SIM110 | ConvertLoopToAny | Use `return any(x for x in y)` instead of `for` loop | 🛠 |
| SIM111 | ConvertLoopToAll | Use `return all(x for x in y)` instead of `for` loop | 🛠 |
| SIM112 | UseCapitalEnvironmentVariables | Use capitalized environment variable `...` instead of `...` | 🛠 |
| SIM115 | OpenFileWithContextHandler | Use context handler for opening files | |
| SIM117 | MultipleWithStatements | Use a single `with` statement with multiple contexts instead of nested `with` statements | |
| SIM118 | KeyInDict | Use `key in dict` instead of `key in dict.keys()` | 🛠 |
| SIM201 | NegateEqualOp | Use `left != right` instead of `not left == right` | 🛠 |
@@ -1084,20 +1089,33 @@ For more, see [pygrep-hooks](https://github.com/pre-commit/pygrep-hooks) on GitH
For more, see [Pylint](https://pypi.org/project/pylint/2.15.7/) on PyPI.
#### Convention (PLC)
| Code | Name | Message | Fix |
| ---- | ---- | ------- | --- |
| PLC0414 | UselessImportAlias | Import alias does not rename original package | 🛠 |
| PLC2201 | MisplacedComparisonConstant | Comparison should be ... | 🛠 |
| PLC3002 | UnnecessaryDirectLambdaCall | Lambda expression called directly. Execute the expression inline instead. | |
#### Error (PLE)
| Code | Name | Message | Fix |
| ---- | ---- | ------- | --- |
| PLE0117 | NonlocalWithoutBinding | Nonlocal name `...` found without binding | |
| PLE0118 | UsedPriorGlobalDeclaration | Name `...` is used prior to global declaration on line 1 | |
| PLE1142 | AwaitOutsideAsync | `await` should be used within an async function | |
#### Refactor (PLR)
| Code | Name | Message | Fix |
| ---- | ---- | ------- | --- |
| PLR0133 | ConstantComparison | Two constants compared in a comparison, consider replacing `0 == 0` | |
| PLR0206 | PropertyWithParameters | Cannot have defined parameters for properties | |
| PLR0402 | ConsiderUsingFromImport | Use `from ... import ...` in lieu of alias | |
| PLR0133 | ConstantComparison | Two constants compared in a comparison, consider replacing `0 == 0` | |
| PLR1701 | ConsiderMergingIsinstance | Merge these isinstance calls: `isinstance(..., (...))` | |
| PLR1722 | UseSysExit | Use `sys.exit()` instead of `exit` | 🛠 |
| PLR2004 | MagicValueComparison | Magic number used in comparison, consider replacing magic with a constant variable | |
#### Warning (PLW)
| Code | Name | Message | Fix |
| ---- | ---- | ------- | --- |
| PLW0120 | UselessElseOnLoop | Else clause on loop without a break statement, remove the else and de-indent all the code inside it | |
| PLW0602 | GlobalVariableNotAssigned | Using global for `...` but no assignment is done | |
@@ -2154,6 +2172,25 @@ line-length = 120
---
#### [`namespace-packages`](#namespace-packages)
Mark the specified directories as namespace packages. For the purpose of
module resolution, Ruff will treat those directories as if they
contained an `__init__.py` file.
**Default value**: `[]`
**Type**: `Vec<PathBuf>`
**Example usage**:
```toml
[tool.ruff]
namespace-packages = ["airflow/providers"]
```
---
#### [`per-file-ignores`](#per-file-ignores)
A list of mappings from file pattern to rule codes or prefixes to

View File

@@ -771,7 +771,7 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
[[package]]
name = "flake8_to_ruff"
version = "0.0.221"
version = "0.0.222"
dependencies = [
"anyhow",
"clap",
@@ -1975,7 +1975,7 @@ dependencies = [
[[package]]
name = "ruff"
version = "0.0.221"
version = "0.0.222"
dependencies = [
"anyhow",
"bincode",

View File

@@ -1,12 +1,8 @@
[package]
name = "flake8-to-ruff"
version = "0.0.221-dev.0"
version = "0.0.222-dev.0"
edition = "2021"
[lib]
name = "flake8_to_ruff"
doctest = false
[dependencies]
anyhow = { version = "1.0.66" }
clap = { version = "4.0.1", features = ["derive"] }

View File

@@ -1,18 +0,0 @@
#![allow(
clippy::collapsible_else_if,
clippy::collapsible_if,
clippy::implicit_hasher,
clippy::match_same_arms,
clippy::missing_errors_doc,
clippy::missing_panics_doc,
clippy::module_name_repetitions,
clippy::must_use_candidate,
clippy::similar_names,
clippy::too_many_lines
)]
#![forbid(unsafe_code)]
pub mod black;
pub mod converter;
mod parser;
pub mod plugin;

View File

@@ -1,4 +1,4 @@
//! Utility to generate Ruff's pyproject.toml section from a Flake8 INI file.
//! Utility to generate Ruff's `pyproject.toml` section from a Flake8 INI file.
#![allow(
clippy::collapsible_else_if,
clippy::collapsible_if,
@@ -18,9 +18,7 @@ use std::path::PathBuf;
use anyhow::Result;
use clap::Parser;
use configparser::ini::Ini;
use flake8_to_ruff::black::parse_black_options;
use flake8_to_ruff::converter;
use flake8_to_ruff::plugin::Plugin;
use ruff::flake8_to_ruff;
#[derive(Parser)]
#[command(
@@ -38,7 +36,7 @@ struct Cli {
pyproject: Option<PathBuf>,
/// List of plugins to enable.
#[arg(long, value_delimiter = ',')]
plugin: Option<Vec<Plugin>>,
plugin: Option<Vec<flake8_to_ruff::Plugin>>,
}
fn main() -> Result<()> {
@@ -52,12 +50,12 @@ fn main() -> Result<()> {
// Read the pyproject.toml file.
let black = cli
.pyproject
.map(parse_black_options)
.map(flake8_to_ruff::parse_black_options)
.transpose()?
.flatten();
// Create Ruff's pyproject.toml section.
let pyproject = converter::convert(&config, black.as_ref(), cli.plugin)?;
let pyproject = flake8_to_ruff::convert(&config, black.as_ref(), cli.plugin)?;
println!("{}", toml_edit::easy::to_string_pretty(&pyproject)?);
Ok(())

View File

@@ -7,7 +7,7 @@ build-backend = "maturin"
[project]
name = "ruff"
version = "0.0.221"
version = "0.0.222"
description = "An extremely fast Python linter, written in Rust."
authors = [
{ name = "Charlie Marsh", email = "charlie.r.marsh@gmail.com" },

View File

@@ -2,6 +2,11 @@ with A() as a: # SIM117
with B() as b:
print("hello")
with A(): # SIM117
with B():
with C():
print("hello")
with A() as a:
a()
with B() as b:

View File

@@ -285,6 +285,16 @@
}
]
},
"namespace-packages": {
"description": "Mark the specified directories as namespace packages. For the purpose of module resolution, Ruff will treat those directories as if they contained an `__init__.py` file.",
"type": [
"array",
"null"
],
"items": {
"type": "string"
}
},
"pep8-naming": {
"description": "Options for the `pep8-naming` plugin.",
"anyOf": [

View File

@@ -1,6 +1,6 @@
[package]
name = "ruff_cli"
version = "0.0.221"
version = "0.0.222"
authors = ["Charlie Marsh <charlie.r.marsh@gmail.com>"]
edition = "2021"
rust-version = "1.65.0"
@@ -17,6 +17,12 @@ name = "ruff"
path = "src/main.rs"
doctest = false
# Since the name of the binary is the same as the name of the `ruff` crate
# running `cargo doc --no-deps --all` results in an `output filename collision`
# See also https://github.com/rust-lang/cargo/issues/6313.
# We therefore disable the documentation generation for the binary.
doc = false
[dependencies]
ruff = { path = ".." }

View File

@@ -2,13 +2,13 @@ use std::path::{Path, PathBuf};
use clap::{command, Parser};
use regex::Regex;
use ruff::fs;
use ruff::logging::LogLevel;
use ruff::registry::{RuleCode, RuleCodePrefix};
use ruff::resolver::ConfigProcessor;
use ruff::settings::types::{
FilePattern, PatternPrefixPair, PerFileIgnore, PythonVersion, SerializationFormat,
};
use ruff::{fs, mccabe};
use rustc_hash::FxHashMap;
#[derive(Debug, Parser)]
@@ -137,9 +137,6 @@ pub struct Cli {
/// formatting.
#[arg(long)]
pub line_length: Option<usize>,
/// Maximum McCabe complexity allowed for a given function.
#[arg(long)]
pub max_complexity: Option<usize>,
/// Enable automatic additions of `noqa` directives to failing lines.
#[arg(
long,
@@ -266,7 +263,6 @@ impl Cli {
fixable: self.fixable,
ignore: self.ignore,
line_length: self.line_length,
max_complexity: self.max_complexity,
per_file_ignores: self.per_file_ignores,
respect_gitignore: resolve_bool_arg(
self.respect_gitignore,
@@ -332,7 +328,6 @@ pub struct Overrides {
pub fixable: Option<Vec<RuleCodePrefix>>,
pub ignore: Option<Vec<RuleCodePrefix>>,
pub line_length: Option<usize>,
pub max_complexity: Option<usize>,
pub per_file_ignores: Option<Vec<PatternPrefixPair>>,
pub respect_gitignore: Option<bool>,
pub select: Option<Vec<RuleCodePrefix>>,
@@ -383,11 +378,6 @@ impl ConfigProcessor for &Overrides {
if let Some(line_length) = &self.line_length {
config.line_length = Some(*line_length);
}
if let Some(max_complexity) = &self.max_complexity {
config.mccabe = Some(mccabe::settings::Options {
max_complexity: Some(*max_complexity),
});
}
if let Some(per_file_ignores) = &self.per_file_ignores {
config.per_file_ignores = Some(collect_per_file_ignores(per_file_ignores.clone()));
}

View File

@@ -19,7 +19,7 @@ use ruff::registry::RuleCode;
use ruff::resolver::{FileDiscovery, PyprojectDiscovery};
use ruff::settings::flags;
use ruff::settings::types::SerializationFormat;
use ruff::{fix, fs, packaging, resolver, violations, warn_user_once};
use ruff::{fix, fs, packaging, resolver, warn_user_once, IOError};
use serde::Serialize;
use walkdir::WalkDir;
@@ -83,6 +83,8 @@ pub fn run(
.flatten()
.map(ignore::DirEntry::path)
.collect::<Vec<_>>(),
&resolver,
pyproject_strategy,
);
let start = Instant::now();
@@ -114,7 +116,7 @@ pub fn run(
let settings = resolver.resolve(path, pyproject_strategy);
if settings.enabled.contains(&RuleCode::E902) {
Diagnostics::new(vec![Message {
kind: violations::IOError(message).into(),
kind: IOError(message).into(),
location: Location::default(),
end_location: Location::default(),
fix: None,
@@ -169,7 +171,7 @@ pub fn run_stdin(
};
let package_root = filename
.and_then(Path::parent)
.and_then(packaging::detect_package_root);
.and_then(|path| packaging::detect_package_root(path, &settings.namespace_packages));
let stdin = read_from_stdin()?;
let mut diagnostics = lint_stdin(filename, package_root, &stdin, settings, autofix)?;
diagnostics.messages.sort_unstable();

View File

@@ -1,6 +1,14 @@
//! This library only exists to enable the Ruff internal tooling (`ruff_dev`)
//! to automatically update the `ruff --help` output in the `README.md`.
//!
//! For the actual Ruff library, see [`ruff`].
#![allow(clippy::must_use_candidate, dead_code)]
mod cli;
// used by ruff_dev::generate_cli_help
pub use cli::Cli;
use clap::CommandFactory;
/// Returns the output of `ruff --help`.
pub fn help() -> String {
cli::Cli::command().render_help().to_string()
}

View File

@@ -180,7 +180,7 @@ fn test_ruff_black_compatibility() -> Result<()> {
// problem. Ruff would add a `# noqa: W292` after the first run, black introduces a
// newline, and ruff removes the `# noqa: W292` again.
.filter(|origin| *origin != RuleOrigin::Ruff)
.map(|origin| origin.codes().iter().map(AsRef::as_ref).join(","))
.map(|origin| origin.prefixes().as_list(","))
.join(",");
let ruff_args = [
"-",

View File

@@ -1,12 +1,8 @@
[package]
name = "ruff_dev"
version = "0.0.221"
version = "0.0.222"
edition = "2021"
[lib]
name = "ruff_dev"
doctest = false
[dependencies]
anyhow = { version = "1.0.66" }
clap = { version = "4.0.1", features = ["derive"] }
@@ -15,9 +11,9 @@ libcst = { git = "https://github.com/charliermarsh/LibCST", rev = "f2f0b7a487a87
once_cell = { version = "1.16.0" }
ruff = { path = ".." }
ruff_cli = { path = "../ruff_cli" }
rustpython-ast = { features = ["unparse"], git = "https://github.com/RustPython/RustPython.git", rev = "d532160333ffeb6dbeca2c2728c2391cd1e53b7f" }
rustpython-common = { git = "https://github.com/RustPython/RustPython.git", rev = "d532160333ffeb6dbeca2c2728c2391cd1e53b7f" }
rustpython-parser = { features = ["lalrpop"], git = "https://github.com/RustPython/RustPython.git", rev = "d532160333ffeb6dbeca2c2728c2391cd1e53b7f" }
rustpython-ast = { features = ["unparse"], git = "https://github.com/RustPython/RustPython.git", rev = "acbc517b55406c76da83d7b2711941d8d3f65b87" }
rustpython-common = { git = "https://github.com/RustPython/RustPython.git", rev = "acbc517b55406c76da83d7b2711941d8d3f65b87" }
rustpython-parser = { features = ["lalrpop"], git = "https://github.com/RustPython/RustPython.git", rev = "acbc517b55406c76da83d7b2711941d8d3f65b87" }
schemars = { version = "0.8.11" }
serde_json = {version="1.0.91"}
strum = { version = "0.24.1", features = ["strum_macros"] }

View File

@@ -1,8 +1,7 @@
//! Generate CLI help.
use anyhow::Result;
use clap::{Args, CommandFactory};
use ruff_cli::Cli as MainCli;
use clap::Args;
use crate::utils::replace_readme_section;
@@ -21,8 +20,7 @@ fn trim_lines(s: &str) -> String {
}
pub fn main(cli: &Cli) -> Result<()> {
let mut cmd = MainCli::command();
let output = trim_lines(cmd.render_help().to_string().trim());
let output = trim_lines(ruff_cli::help().trim());
if cli.dry_run {
print!("{output}");

View File

@@ -2,8 +2,7 @@
use anyhow::Result;
use clap::Args;
use itertools::Itertools;
use ruff::registry::{RuleCode, RuleOrigin};
use ruff::registry::{Prefixes, RuleCodePrefix, RuleOrigin};
use strum::IntoEnumIterator;
use crate::utils::replace_readme_section;
@@ -21,12 +20,33 @@ pub struct Cli {
pub(crate) dry_run: bool,
}
fn generate_table(table_out: &mut String, prefix: &RuleCodePrefix) {
table_out.push_str("| Code | Name | Message | Fix |");
table_out.push('\n');
table_out.push_str("| ---- | ---- | ------- | --- |");
table_out.push('\n');
for rule_code in prefix.codes() {
let kind = rule_code.kind();
let fix_token = if kind.fixable() { "🛠" } else { "" };
table_out.push_str(&format!(
"| {} | {} | {} | {} |",
kind.code().as_ref(),
kind.as_ref(),
kind.summary().replace('|', r"\|"),
fix_token
));
table_out.push('\n');
}
table_out.push('\n');
}
pub fn main(cli: &Cli) -> Result<()> {
// Generate the table string.
let mut table_out = String::new();
let mut toc_out = String::new();
for origin in RuleOrigin::iter() {
let codes_csv: String = origin.codes().iter().map(AsRef::as_ref).join(", ");
let prefixes = origin.prefixes();
let codes_csv: String = prefixes.as_list(", ");
table_out.push_str(&format!("### {} ({codes_csv})", origin.title()));
table_out.push('\n');
table_out.push('\n');
@@ -50,26 +70,16 @@ pub fn main(cli: &Cli) -> Result<()> {
table_out.push('\n');
}
table_out.push_str("| Code | Name | Message | Fix |");
table_out.push('\n');
table_out.push_str("| ---- | ---- | ------- | --- |");
table_out.push('\n');
for rule_code in RuleCode::iter() {
if rule_code.origin() == origin {
let kind = rule_code.kind();
let fix_token = if kind.fixable() { "🛠" } else { "" };
table_out.push_str(&format!(
"| {} | {} | {} | {} |",
kind.code().as_ref(),
kind.as_ref(),
kind.summary().replace('|', r"\|"),
fix_token
));
table_out.push('\n');
match prefixes {
Prefixes::Single(prefix) => generate_table(&mut table_out, &prefix),
Prefixes::Multiple(entries) => {
for (prefix, category) in entries {
table_out.push_str(&format!("#### {category} ({})", prefix.as_ref()));
table_out.push('\n');
generate_table(&mut table_out, &prefix);
}
}
}
table_out.push('\n');
}
if cli.dry_run {

View File

@@ -1,24 +0,0 @@
#![allow(
clippy::collapsible_else_if,
clippy::collapsible_if,
clippy::implicit_hasher,
clippy::match_same_arms,
clippy::missing_errors_doc,
clippy::missing_panics_doc,
clippy::module_name_repetitions,
clippy::must_use_candidate,
clippy::similar_names,
clippy::too_many_lines
)]
#![forbid(unsafe_code)]
pub mod generate_all;
pub mod generate_cli_help;
pub mod generate_json_schema;
pub mod generate_options;
pub mod generate_rules_table;
pub mod print_ast;
pub mod print_cst;
pub mod print_tokens;
pub mod round_trip;
mod utils;

View File

@@ -1,3 +1,6 @@
//! This crate implements an internal CLI for developers of Ruff.
//!
//! Within the ruff repository you can run it with `cargo dev`.
#![allow(
clippy::collapsible_else_if,
clippy::collapsible_if,
@@ -12,12 +15,19 @@
)]
#![forbid(unsafe_code)]
mod generate_all;
mod generate_cli_help;
mod generate_json_schema;
mod generate_options;
mod generate_rules_table;
mod print_ast;
mod print_cst;
mod print_tokens;
mod round_trip;
mod utils;
use anyhow::Result;
use clap::{Parser, Subcommand};
use ruff_dev::{
generate_all, generate_cli_help, generate_json_schema, generate_options, generate_rules_table,
print_ast, print_cst, print_tokens, round_trip,
};
#[derive(Parser)]
#[command(author, version, about, long_about = None)]

View File

@@ -5,8 +5,7 @@ use std::path::PathBuf;
use anyhow::Result;
use clap::Args;
use ruff::source_code::{Generator, Locator, Stylist};
use rustpython_parser::parser;
use ruff::source_code::round_trip;
#[derive(Args)]
pub struct Cli {
@@ -17,11 +16,6 @@ pub struct Cli {
pub fn main(cli: &Cli) -> Result<()> {
let contents = fs::read_to_string(&cli.file)?;
let python_ast = parser::parse_program(&contents, &cli.file.to_string_lossy())?;
let locator = Locator::new(&contents);
let stylist = Stylist::from_contents(&contents, &locator);
let mut generator: Generator = (&stylist).into();
generator.unparse_suite(&python_ast);
println!("{}", generator.generate());
println!("{}", round_trip(&contents, &cli.file.to_string_lossy())?);
Ok(())
}

View File

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

View File

@@ -1,3 +1,4 @@
//! This crate implements internal macros for the `ruff` library.
#![allow(
clippy::collapsible_else_if,
clippy::collapsible_if,

View File

@@ -1,5 +1,5 @@
//! An equivalent object hierarchy to the `Expr` hierarchy, but with the ability
//! to compare expressions for equality (via `Eq` and `Hash`).
//! An equivalent object hierarchy to the [`Expr`] hierarchy, but with the
//! ability to compare expressions for equality (via [`Eq`] and [`Hash`]).
use num_bigint::BigInt;
use rustpython_ast::{

View File

@@ -197,7 +197,7 @@ where
static DUNDER_REGEX: Lazy<Regex> = Lazy::new(|| Regex::new(r"__[^\s]+__").unwrap());
/// Return `true` if the `Stmt` is an assignment to a dunder (like `__all__`).
/// Return `true` if the [`Stmt`] is an assignment to a dunder (like `__all__`).
pub fn is_assignment_to_a_dunder(stmt: &Stmt) -> bool {
// Check whether it's an assignment to a dunder, with or without a type
// annotation. This is what pycodestyle (as of 2.9.1) does.
@@ -219,7 +219,7 @@ pub fn is_assignment_to_a_dunder(stmt: &Stmt) -> bool {
}
}
/// Return `true` if the `Expr` is a singleton (`None`, `True`, `False`, or
/// Return `true` if the [`Expr`] is a singleton (`None`, `True`, `False`, or
/// `...`).
pub fn is_singleton(expr: &Expr) -> bool {
matches!(
@@ -231,7 +231,7 @@ pub fn is_singleton(expr: &Expr) -> bool {
)
}
/// Return `true` if the `Expr` is a constant or tuple of constants.
/// Return `true` if the [`Expr`] is a constant or tuple of constants.
pub fn is_constant(expr: &Expr) -> bool {
match &expr.node {
ExprKind::Constant { .. } => true,
@@ -240,13 +240,13 @@ pub fn is_constant(expr: &Expr) -> bool {
}
}
/// Return `true` if the `Expr` is a non-singleton constant.
/// Return `true` if the [`Expr`] is a non-singleton constant.
pub fn is_constant_non_singleton(expr: &Expr) -> bool {
is_constant(expr) && !is_singleton(expr)
}
/// Return the `Keyword` with the given name, if it's present in the list of
/// `Keyword` arguments.
/// Return the [`Keyword`] with the given name, if it's present in the list of
/// [`Keyword`] arguments.
pub fn find_keyword<'a>(keywords: &'a [Keyword], keyword_name: &str) -> Option<&'a Keyword> {
keywords.iter().find(|keyword| {
let KeywordData { arg, .. } = &keyword.node;
@@ -254,7 +254,7 @@ pub fn find_keyword<'a>(keywords: &'a [Keyword], keyword_name: &str) -> Option<&
})
}
/// Return `true` if an `Expr` is `None`.
/// Return `true` if an [`Expr`] is `None`.
pub fn is_const_none(expr: &Expr) -> bool {
matches!(
&expr.node,
@@ -622,6 +622,19 @@ pub fn preceded_by_continuation(stmt: &Stmt, locator: &Locator) -> bool {
false
}
/// Return the `Range` of the first `Tok::Colon` token in a `Range`.
pub fn first_colon_range(range: Range, locator: &Locator) -> Option<Range> {
let contents = locator.slice_source_code_range(&range);
let range = lexer::make_tokenizer_located(&contents, range.location)
.flatten()
.find(|(_, kind, _)| matches!(kind, Tok::Colon))
.map(|(location, _, end_location)| Range {
location,
end_location,
});
range
}
/// Return `true` if a `Stmt` appears to be part of a multi-statement line, with
/// other statements preceding it.
pub fn preceded_by_multi_statement_line(stmt: &Stmt, locator: &Locator) -> bool {
@@ -708,7 +721,9 @@ mod tests {
use rustpython_ast::Location;
use rustpython_parser::parser;
use crate::ast::helpers::{else_range, identifier_range, match_trailing_content};
use crate::ast::helpers::{
else_range, first_colon_range, identifier_range, match_trailing_content,
};
use crate::ast::types::Range;
use crate::source_code::Locator;
@@ -839,4 +854,19 @@ else:
assert_eq!(range.end_location.column(), 4);
Ok(())
}
#[test]
fn test_first_colon_range() {
let contents = "with a: pass";
let locator = Locator::new(contents);
let range = first_colon_range(
Range::new(Location::new(1, 0), Location::new(1, contents.len())),
&locator,
)
.unwrap();
assert_eq!(range.location.row(), 1);
assert_eq!(range.location.column(), 6);
assert_eq!(range.end_location.row(), 1);
assert_eq!(range.end_location.column(), 7);
}
}

View File

@@ -96,7 +96,7 @@ impl<'a> Visitor<'a> for GlobalVisitor<'a> {
}
}
/// Extract a map from global name to its last-defining `Stmt`.
/// Extract a map from global name to its last-defining [`Stmt`].
pub fn extract_globals(body: &[Stmt]) -> FxHashMap<&str, &Stmt> {
let mut visitor = GlobalVisitor::default();
for stmt in body {
@@ -197,12 +197,12 @@ pub fn is_unpacking_assignment(parent: &Stmt, child: &Expr) -> bool {
pub type LocatedCmpop<U = ()> = Located<Cmpop, U>;
/// Extract all `Cmpop` operators from a source code snippet, with appropriate
/// Extract all [`Cmpop`] operators from a source code snippet, with appropriate
/// ranges.
///
/// `RustPython` doesn't include line and column information on `Cmpop` nodes.
/// `RustPython` doesn't include line and column information on [`Cmpop`] nodes.
/// `CPython` doesn't either. This method iterates over the token stream and
/// re-identifies `Cmpop` nodes, annotating them with valid ranges.
/// re-identifies [`Cmpop`] nodes, annotating them with valid ranges.
pub fn locate_cmpops(contents: &str) -> Vec<LocatedCmpop> {
let mut tok_iter = lexer::make_tokenizer(contents).flatten().peekable();
let mut ops: Vec<LocatedCmpop> = vec![];

View File

@@ -127,7 +127,7 @@ pub enum BindingKind<'a> {
pub struct Binding<'a> {
pub kind: BindingKind<'a>,
pub range: Range,
/// The statement in which the `Binding` was defined.
/// The statement in which the [`Binding`] was defined.
pub source: Option<RefEquality<'a, Stmt>>,
/// Tuple of (scope index, range) indicating the scope and range at which
/// the binding was last used.

View File

@@ -29,20 +29,20 @@ use crate::python::future::ALL_FEATURE_NAMES;
use crate::python::typing;
use crate::python::typing::SubscriptKind;
use crate::registry::{Diagnostic, RuleCode};
use crate::rules::{
flake8_2020, flake8_annotations, flake8_bandit, flake8_blind_except, flake8_boolean_trap,
flake8_bugbear, flake8_builtins, flake8_comprehensions, flake8_datetimez, flake8_debugger,
flake8_errmsg, flake8_implicit_str_concat, flake8_import_conventions, flake8_pie, flake8_print,
flake8_pytest_style, flake8_return, flake8_simplify, flake8_tidy_imports,
flake8_unused_arguments, mccabe, pandas_vet, pep8_naming, pycodestyle, pydocstyle, pyflakes,
pygrep_hooks, pylint, pyupgrade, ruff,
};
use crate::settings::types::PythonVersion;
use crate::settings::{flags, Settings};
use crate::source_code::{Locator, Stylist};
use crate::violations::DeferralKeyword;
use crate::visibility::{module_visibility, transition_scope, Modifier, Visibility, VisibleScope};
use crate::{
autofix, docstrings, flake8_2020, flake8_annotations, flake8_bandit, flake8_blind_except,
flake8_boolean_trap, flake8_bugbear, flake8_builtins, flake8_comprehensions, flake8_datetimez,
flake8_debugger, flake8_errmsg, flake8_implicit_str_concat, flake8_import_conventions,
flake8_pie, flake8_print, flake8_pytest_style, flake8_return, flake8_simplify,
flake8_tidy_imports, flake8_unused_arguments, mccabe, noqa, pandas_vet, pep8_naming,
pycodestyle, pydocstyle, pyflakes, pygrep_hooks, pylint, pyupgrade, ruff, violations,
visibility,
};
use crate::{autofix, docstrings, noqa, violations, visibility};
const GLOBAL_SCOPE_INDEX: usize = 0;
@@ -1283,7 +1283,12 @@ where
flake8_pytest_style::rules::complex_raises(self, stmt, items, body);
}
if self.settings.enabled.contains(&RuleCode::SIM117) {
flake8_simplify::rules::multiple_with_statements(self, stmt);
flake8_simplify::rules::multiple_with_statements(
self,
stmt,
body,
self.current_stmt_parent().map(|parent| parent.0),
);
}
}
StmtKind::While { body, orelse, .. } => {

View File

@@ -6,9 +6,9 @@ use rustpython_parser::ast::Suite;
use crate::ast::visitor::Visitor;
use crate::directives::IsortDirectives;
use crate::isort;
use crate::isort::track::{Block, ImportTracker};
use crate::registry::{Diagnostic, RuleCode};
use crate::rules::isort;
use crate::rules::isort::track::{Block, ImportTracker};
use crate::settings::{flags, Settings};
use crate::source_code::{Locator, Stylist};

View File

@@ -1,9 +1,11 @@
//! Lint rules based on checking raw physical lines.
use crate::pycodestyle::rules::{doc_line_too_long, line_too_long, no_newline_at_end_of_file};
use crate::pygrep_hooks::rules::{blanket_noqa, blanket_type_ignore};
use crate::pyupgrade::rules::unnecessary_coding_comment;
use crate::registry::{Diagnostic, RuleCode};
use crate::rules::pycodestyle::rules::{
doc_line_too_long, line_too_long, no_newline_at_end_of_file,
};
use crate::rules::pygrep_hooks::rules::{blanket_noqa, blanket_type_ignore};
use crate::rules::pyupgrade::rules::unnecessary_coding_comment;
use crate::settings::{flags, Settings};
pub fn check_lines(

View File

@@ -4,10 +4,10 @@ use rustpython_parser::lexer::{LexResult, Tok};
use crate::lex::docstring_detection::StateMachine;
use crate::registry::{Diagnostic, RuleCode};
use crate::ruff::rules::Context;
use crate::rules::ruff::rules::Context;
use crate::rules::{eradicate, flake8_implicit_str_concat, flake8_quotes, pycodestyle, ruff};
use crate::settings::{flags, Settings};
use crate::source_code::Locator;
use crate::{eradicate, flake8_implicit_str_concat, flake8_quotes, pycodestyle, ruff};
pub fn check_tokens(
locator: &Locator,
@@ -105,7 +105,7 @@ pub fn check_tokens(
// ISC001, ISC002
if enforce_implicit_string_concatenation {
diagnostics.extend(
flake8_implicit_str_concat::rules::implicit(tokens, locator)
flake8_implicit_str_concat::rules::implicit(tokens)
.into_iter()
.filter(|diagnostic| settings.enabled.contains(diagnostic.kind.code())),
);

View File

@@ -1,6 +0,0 @@
---
source: src/flake8_annotations/mod.rs
expression: diagnostics
---
[]

View File

@@ -1,6 +0,0 @@
---
source: src/flake8_annotations/mod.rs
expression: checks
---
[]

View File

@@ -1,6 +0,0 @@
---
source: src/flake8_quotes/mod.rs
expression: checks
---
[]

View File

@@ -1,6 +0,0 @@
---
source: src/flake8_quotes/mod.rs
expression: checks
---
[]

View File

@@ -1,6 +0,0 @@
---
source: src/flake8_quotes/mod.rs
expression: checks
---
[]

View File

@@ -1,6 +0,0 @@
---
source: src/flake8_quotes/mod.rs
expression: checks
---
[]

View File

@@ -1,22 +0,0 @@
use rustpython_ast::{Stmt, StmtKind};
use crate::ast::types::Range;
use crate::checkers::ast::Checker;
use crate::registry::Diagnostic;
use crate::violations;
/// SIM117
pub fn multiple_with_statements(checker: &mut Checker, stmt: &Stmt) {
let StmtKind::With { body, .. } = &stmt.node else {
return;
};
if body.len() != 1 {
return;
}
if matches!(body[0].node, StmtKind::With { .. }) {
checker.diagnostics.push(Diagnostic::new(
violations::MultipleWithStatements,
Range::from_located(stmt),
));
}
}

View File

@@ -1,15 +0,0 @@
---
source: src/flake8_simplify/mod.rs
expression: checks
---
- kind:
MultipleWithStatements: ~
location:
row: 1
column: 0
end_location:
row: 3
column: 22
fix: ~
parent: ~

View File

@@ -3,9 +3,10 @@
use std::path::Path;
use anyhow::Result;
use ruff::settings::types::PythonVersion;
use serde::{Deserialize, Serialize};
use crate::settings::types::PythonVersion;
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Default)]
pub struct Black {
#[serde(alias = "line-length", alias = "line_length")]

View File

@@ -2,24 +2,26 @@ use std::collections::{BTreeSet, HashMap};
use anyhow::Result;
use colored::Colorize;
use ruff::flake8_pytest_style::types::{
use super::black::Black;
use super::plugin::Plugin;
use super::{parser, plugin};
use crate::registry::RuleCodePrefix;
use crate::rules::flake8_pytest_style::types::{
ParametrizeNameType, ParametrizeValuesRowType, ParametrizeValuesType,
};
use ruff::flake8_quotes::settings::Quote;
use ruff::flake8_tidy_imports::settings::Strictness;
use ruff::pydocstyle::settings::Convention;
use ruff::registry::RuleCodePrefix;
use ruff::settings::options::Options;
use ruff::settings::pyproject::Pyproject;
use ruff::{
use crate::rules::flake8_quotes::settings::Quote;
use crate::rules::flake8_tidy_imports::settings::Strictness;
use crate::rules::pydocstyle::settings::Convention;
use crate::rules::{
flake8_annotations, flake8_bugbear, flake8_errmsg, flake8_pytest_style, flake8_quotes,
flake8_tidy_imports, mccabe, pep8_naming, pydocstyle, warn_user,
flake8_tidy_imports, mccabe, pep8_naming, pydocstyle,
};
use crate::settings::options::Options;
use crate::settings::pyproject::Pyproject;
use crate::warn_user;
use crate::black::Black;
use crate::plugin::Plugin;
use crate::{parser, plugin};
#[allow(clippy::unnecessary_wraps)]
pub fn convert(
config: &HashMap<String, HashMap<String, Option<String>>>,
black: Option<&Black>,
@@ -388,14 +390,14 @@ mod tests {
use std::collections::HashMap;
use anyhow::Result;
use ruff::pydocstyle::settings::Convention;
use ruff::registry::RuleCodePrefix;
use ruff::settings::options::Options;
use ruff::settings::pyproject::Pyproject;
use ruff::{flake8_quotes, pydocstyle};
use crate::converter::convert;
use crate::plugin::Plugin;
use super::super::plugin::Plugin;
use super::convert;
use crate::registry::RuleCodePrefix;
use crate::rules::pydocstyle::settings::Convention;
use crate::rules::{flake8_quotes, pydocstyle};
use crate::settings::options::Options;
use crate::settings::pyproject::Pyproject;
#[test]
fn it_converts_empty() -> Result<()> {
@@ -423,6 +425,7 @@ mod tests {
ignore: Some(vec![]),
ignore_init_module_imports: None,
line_length: None,
namespace_packages: None,
per_file_ignores: None,
required_version: None,
respect_gitignore: None,
@@ -488,6 +491,7 @@ mod tests {
ignore: Some(vec![]),
ignore_init_module_imports: None,
line_length: Some(100),
namespace_packages: None,
per_file_ignores: None,
required_version: None,
respect_gitignore: None,
@@ -553,6 +557,7 @@ mod tests {
ignore: Some(vec![]),
ignore_init_module_imports: None,
line_length: Some(100),
namespace_packages: None,
per_file_ignores: None,
required_version: None,
respect_gitignore: None,
@@ -618,6 +623,7 @@ mod tests {
ignore: Some(vec![]),
ignore_init_module_imports: None,
line_length: None,
namespace_packages: None,
per_file_ignores: None,
required_version: None,
respect_gitignore: None,
@@ -683,6 +689,7 @@ mod tests {
ignore: Some(vec![]),
ignore_init_module_imports: None,
line_length: None,
namespace_packages: None,
per_file_ignores: None,
required_version: None,
respect_gitignore: None,
@@ -756,6 +763,7 @@ mod tests {
ignore: Some(vec![]),
ignore_init_module_imports: None,
line_length: None,
namespace_packages: None,
per_file_ignores: None,
required_version: None,
respect_gitignore: None,
@@ -824,6 +832,7 @@ mod tests {
ignore: Some(vec![]),
ignore_init_module_imports: None,
line_length: None,
namespace_packages: None,
per_file_ignores: None,
required_version: None,
respect_gitignore: None,

View File

@@ -0,0 +1,8 @@
mod black;
mod converter;
mod parser;
mod plugin;
pub use black::parse_black_options;
pub use converter::convert;
pub use plugin::Plugin;

View File

@@ -4,11 +4,12 @@ use anyhow::{bail, Result};
use colored::Colorize;
use once_cell::sync::Lazy;
use regex::Regex;
use ruff::registry::{RuleCodePrefix, PREFIX_REDIRECTS};
use ruff::settings::types::PatternPrefixPair;
use ruff::warn_user;
use rustc_hash::FxHashMap;
use crate::registry::{RuleCodePrefix, PREFIX_REDIRECTS};
use crate::settings::types::PatternPrefixPair;
use crate::warn_user;
static COMMA_SEPARATED_LIST_RE: Lazy<Regex> = Lazy::new(|| Regex::new(r"[,\s]").unwrap());
/// Parse a comma-separated list of `RuleCodePrefix` values (e.g.,
@@ -203,10 +204,10 @@ pub fn collect_per_file_ignores(
#[cfg(test)]
mod tests {
use anyhow::Result;
use ruff::registry::RuleCodePrefix;
use ruff::settings::types::PatternPrefixPair;
use crate::parser::{parse_files_to_codes_mapping, parse_prefix_codes, parse_strings};
use super::{parse_files_to_codes_mapping, parse_prefix_codes, parse_strings};
use crate::registry::RuleCodePrefix;
use crate::settings::types::PatternPrefixPair;
#[test]
fn it_parses_prefix_codes() {

View File

@@ -3,7 +3,8 @@ use std::fmt;
use std::str::FromStr;
use anyhow::anyhow;
use ruff::registry::RuleCodePrefix;
use crate::registry::RuleCodePrefix;
#[derive(Clone, Ord, PartialOrd, Eq, PartialEq)]
pub enum Plugin {
@@ -298,7 +299,7 @@ pub fn resolve_select(plugins: &[Plugin]) -> BTreeSet<RuleCodePrefix> {
mod tests {
use std::collections::HashMap;
use crate::plugin::{infer_plugins_from_options, Plugin};
use super::{infer_plugins_from_options, Plugin};
#[test]
fn it_infers_plugins() {

View File

@@ -1,6 +0,0 @@
---
source: src/isort/mod.rs
expression: checks
---
[]

View File

@@ -1,6 +0,0 @@
---
source: src/isort/mod.rs
expression: diagnostics
---
[]

View File

@@ -1,6 +0,0 @@
---
source: src/isort/mod.rs
expression: diagnostics
---
[]

View File

@@ -1,6 +0,0 @@
---
source: src/isort/mod.rs
expression: diagnostics
---
[]

View File

@@ -1,6 +0,0 @@
---
source: src/isort/mod.rs
expression: checks
---
[]

View File

@@ -1,6 +0,0 @@
---
source: src/isort/mod.rs
expression: checks
---
[]

View File

@@ -1,6 +0,0 @@
---
source: src/isort/mod.rs
expression: diagnostics
---
[]

View File

@@ -1,6 +0,0 @@
---
source: src/isort/mod.rs
expression: diagnostics
---
[]

View File

@@ -1,6 +0,0 @@
---
source: src/isort/mod.rs
expression: checks
---
[]

View File

@@ -43,7 +43,10 @@ impl StateMachine {
}
pub fn consume(&mut self, tok: &Tok) -> bool {
if matches!(tok, Tok::Newline | Tok::Indent | Tok::Dedent) {
if matches!(
tok,
Tok::NonLogicalNewline | Tok::Newline | Tok::Indent | Tok::Dedent | Tok::Comment(..)
) {
return false;
}

View File

@@ -1,3 +1,9 @@
//! This is the library for the [Ruff] Python linter.
//!
//! **The API is currently completely unstable**
//! and subject to change drastically.
//!
//! [Ruff]: https://github.com/charliermarsh/ruff
#![allow(
clippy::collapsible_else_if,
clippy::collapsible_if,
@@ -14,66 +20,36 @@
extern crate core;
pub mod ast;
pub mod autofix;
mod ast;
mod autofix;
pub mod cache;
mod checkers;
mod cst;
pub mod directives;
mod directives;
mod doc_lines;
mod docstrings;
mod eradicate;
pub mod fix;
mod flake8_2020;
pub mod flake8_annotations;
pub mod flake8_bandit;
mod flake8_blind_except;
pub mod flake8_boolean_trap;
pub mod flake8_bugbear;
mod flake8_builtins;
mod flake8_comprehensions;
mod flake8_datetimez;
mod flake8_debugger;
pub mod flake8_errmsg;
mod flake8_implicit_str_concat;
mod flake8_import_conventions;
pub mod flake8_pie;
mod flake8_print;
pub mod flake8_pytest_style;
pub mod flake8_quotes;
mod flake8_return;
mod flake8_simplify;
pub mod flake8_tidy_imports;
mod flake8_unused_arguments;
pub mod flake8_to_ruff;
pub mod fs;
mod isort;
mod lex;
pub mod linter;
pub mod logging;
pub mod mccabe;
pub mod message;
mod noqa;
mod pandas_vet;
pub mod pep8_naming;
mod pycodestyle;
pub mod pydocstyle;
mod pyflakes;
mod pygrep_hooks;
mod pylint;
mod python;
mod pyupgrade;
pub mod registry;
pub mod resolver;
mod ruff;
pub mod rustpython_helpers;
mod rules;
mod rustpython_helpers;
pub mod settings;
pub mod source_code;
mod vendor;
mod violation;
pub mod violations;
mod violations;
mod visibility;
use cfg_if::cfg_if;
pub use violations::IOError;
cfg_if! {
if #[cfg(not(target_family = "wasm"))] {

View File

@@ -51,7 +51,7 @@ pub fn check(path: &Path, contents: &str, autofix: bool) -> Result<Vec<Diagnosti
// Generate diagnostics.
let diagnostics = check_path(
path,
packaging::detect_package_root(path),
packaging::detect_package_root(path, &settings.namespace_packages),
contents,
tokens,
&locator,

View File

@@ -5,19 +5,20 @@ use rustpython_parser::lexer::LexResult;
use serde::Serialize;
use wasm_bindgen::prelude::*;
use crate::directives;
use crate::linter::check_path;
use crate::registry::{RuleCode, RuleCodePrefix};
use crate::rules::{
flake8_annotations, flake8_bandit, flake8_bugbear, flake8_errmsg, flake8_import_conventions,
flake8_pytest_style, flake8_quotes, flake8_tidy_imports, flake8_unused_arguments, isort,
mccabe, pep8_naming, pycodestyle, pydocstyle, pyupgrade,
};
use crate::rustpython_helpers::tokenize;
use crate::settings::configuration::Configuration;
use crate::settings::options::Options;
use crate::settings::types::PythonVersion;
use crate::settings::{flags, Settings};
use crate::source_code::{Locator, Stylist};
use crate::{
directives, flake8_annotations, flake8_bandit, flake8_bugbear, flake8_errmsg,
flake8_import_conventions, flake8_pytest_style, flake8_quotes, flake8_tidy_imports,
flake8_unused_arguments, isort, mccabe, pep8_naming, pycodestyle, pydocstyle, pyupgrade,
};
const VERSION: &str = env!("CARGO_PKG_VERSION");
@@ -105,14 +106,15 @@ pub fn defaultSettings() -> Result<JsValue, JsValue> {
force_exclude: None,
format: None,
ignore_init_module_imports: None,
namespace_packages: None,
per_file_ignores: None,
required_version: None,
respect_gitignore: None,
show_source: None,
src: None,
unfixable: None,
typing_modules: None,
task_tags: None,
typing_modules: None,
unfixable: None,
update_check: None,
// Use default options for all plugins.
flake8_annotations: Some(flake8_annotations::settings::Settings::default().into()),

View File

@@ -1,6 +0,0 @@
---
source: src/mccabe/mod.rs
expression: checks
---
[]

View File

@@ -1,9 +1,11 @@
//! Detect Python package roots and file associations.
use std::path::Path;
use std::path::{Path, PathBuf};
use rustc_hash::FxHashMap;
use crate::resolver::{PyprojectDiscovery, Resolver};
// If we have a Python package layout like:
// - root/
// - foo/
@@ -27,15 +29,21 @@ use rustc_hash::FxHashMap;
/// Return `true` if the directory at the given `Path` appears to be a Python
/// package.
pub fn is_package(path: &Path) -> bool {
pub fn is_package(path: &Path, namespace_packages: &[PathBuf]) -> bool {
path.join("__init__.py").is_file()
|| namespace_packages
.iter()
.any(|namespace_package| namespace_package == path)
}
/// Return the package root for the given Python file.
pub fn detect_package_root(path: &Path) -> Option<&Path> {
pub fn detect_package_root<'a>(
path: &'a Path,
namespace_packages: &'a [PathBuf],
) -> Option<&'a Path> {
let mut current = None;
for parent in path.ancestors() {
if !is_package(parent) {
if !is_package(parent, namespace_packages) {
return current;
}
current = Some(parent);
@@ -46,21 +54,23 @@ pub fn detect_package_root(path: &Path) -> Option<&Path> {
/// A wrapper around `is_package` to cache filesystem lookups.
fn is_package_with_cache<'a>(
path: &'a Path,
namespace_packages: &'a [PathBuf],
package_cache: &mut FxHashMap<&'a Path, bool>,
) -> bool {
*package_cache
.entry(path)
.or_insert_with(|| is_package(path))
.or_insert_with(|| is_package(path, namespace_packages))
}
/// A wrapper around `detect_package_root` to cache filesystem lookups.
fn detect_package_root_with_cache<'a>(
path: &'a Path,
namespace_packages: &'a [PathBuf],
package_cache: &mut FxHashMap<&'a Path, bool>,
) -> Option<&'a Path> {
let mut current = None;
for parent in path.ancestors() {
if !is_package_with_cache(parent, package_cache) {
if !is_package_with_cache(parent, namespace_packages, package_cache) {
return current;
}
current = Some(parent);
@@ -69,7 +79,11 @@ fn detect_package_root_with_cache<'a>(
}
/// Return a mapping from Python file to its package root.
pub fn detect_package_roots<'a>(files: &[&'a Path]) -> FxHashMap<&'a Path, Option<&'a Path>> {
pub fn detect_package_roots<'a>(
files: &[&'a Path],
resolver: &'a Resolver,
pyproject_strategy: &'a PyprojectDiscovery,
) -> FxHashMap<&'a Path, Option<&'a Path>> {
// Pre-populate the module cache, since the list of files could (but isn't
// required to) contain some `__init__.py` files.
let mut package_cache: FxHashMap<&Path, bool> = FxHashMap::default();
@@ -84,13 +98,16 @@ pub fn detect_package_roots<'a>(files: &[&'a Path]) -> FxHashMap<&'a Path, Optio
// Search for the package root for each file.
let mut package_roots: FxHashMap<&Path, Option<&Path>> = FxHashMap::default();
for file in files {
let namespace_packages = &resolver
.resolve(file, pyproject_strategy)
.namespace_packages;
if let Some(package) = file.parent() {
if package_roots.contains_key(package) {
continue;
}
package_roots.insert(
package,
detect_package_root_with_cache(package, &mut package_cache),
detect_package_root_with_cache(package, namespace_packages, &mut package_cache),
);
}
}
@@ -111,6 +128,7 @@ mod tests {
PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.join("resources/test/package/src/package")
.as_path(),
&[],
),
Some(
PathBuf::from(env!("CARGO_MANIFEST_DIR"))
@@ -124,6 +142,7 @@ mod tests {
PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.join("resources/test/project/python_modules/core/core")
.as_path(),
&[],
),
Some(
PathBuf::from(env!("CARGO_MANIFEST_DIR"))
@@ -137,6 +156,7 @@ mod tests {
PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.join("resources/test/project/examples/docs/docs/concepts")
.as_path(),
&[],
),
Some(
PathBuf::from(env!("CARGO_MANIFEST_DIR"))
@@ -150,6 +170,7 @@ mod tests {
PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.join("setup.py")
.as_path(),
&[],
),
None,
);

View File

@@ -1,6 +0,0 @@
---
source: src/pycodestyle/mod.rs
expression: checks
---
[]

View File

@@ -1,6 +0,0 @@
---
source: src/pycodestyle/mod.rs
expression: checks
---
[]

View File

@@ -1,6 +0,0 @@
---
source: src/pycodestyle/mod.rs
expression: checks
---
[]

View File

@@ -1,6 +0,0 @@
---
source: src/pycodestyle/mod.rs
expression: checks
---
[]

View File

@@ -1,6 +0,0 @@
---
source: src/pydocstyle/mod.rs
expression: checks
---
[]

View File

@@ -1,6 +0,0 @@
---
source: src/pydocstyle/mod.rs
expression: checks
---
[]

View File

@@ -1,6 +0,0 @@
---
source: src/pydocstyle/mod.rs
expression: checks
---
[]

View File

@@ -1,6 +0,0 @@
---
source: src/pydocstyle/mod.rs
expression: checks
---
[]

View File

@@ -1,6 +0,0 @@
---
source: src/pydocstyle/mod.rs
expression: checks
---
[]

View File

@@ -1,6 +0,0 @@
---
source: src/pydocstyle/mod.rs
expression: checks
---
[]

View File

@@ -1,6 +0,0 @@
---
source: src/pydocstyle/mod.rs
expression: checks
---
[]

View File

@@ -1,6 +0,0 @@
---
source: src/pydocstyle/mod.rs
expression: checks
---
[]

View File

@@ -1,6 +0,0 @@
---
source: src/pydocstyle/mod.rs
expression: checks
---
[]

View File

@@ -1,6 +0,0 @@
---
source: src/pydocstyle/mod.rs
expression: checks
---
[]

View File

@@ -1,6 +0,0 @@
---
source: src/pyflakes/mod.rs
expression: checks
---
[]

View File

@@ -1,6 +0,0 @@
---
source: src/pyflakes/mod.rs
expression: checks
---
[]

View File

@@ -1,6 +0,0 @@
---
source: src/pyflakes/mod.rs
expression: checks
---
[]

View File

@@ -1,6 +0,0 @@
---
source: src/pyflakes/mod.rs
expression: checks
---
[]

View File

@@ -1,6 +0,0 @@
---
source: src/pyflakes/mod.rs
expression: checks
---
[]

View File

@@ -1,6 +0,0 @@
---
source: src/pyflakes/mod.rs
expression: checks
---
[]

View File

@@ -1,6 +0,0 @@
---
source: src/pyflakes/mod.rs
expression: checks
---
[]

View File

@@ -1,6 +0,0 @@
---
source: src/pyflakes/mod.rs
expression: checks
---
[]

View File

@@ -1,6 +0,0 @@
---
source: src/pyflakes/mod.rs
expression: checks
---
[]

View File

@@ -1,6 +0,0 @@
---
source: src/pyflakes/mod.rs
expression: checks
---
[]

View File

@@ -1,6 +0,0 @@
---
source: src/pyflakes/mod.rs
expression: checks
---
[]

View File

@@ -1,6 +0,0 @@
---
source: src/pyflakes/mod.rs
expression: checks
---
[]

View File

@@ -1,6 +0,0 @@
---
source: src/pyflakes/mod.rs
expression: checks
---
[]

View File

@@ -1,6 +0,0 @@
---
source: src/pyflakes/mod.rs
expression: checks
---
[]

View File

@@ -1,6 +0,0 @@
---
source: src/pyflakes/mod.rs
expression: checks
---
[]

View File

@@ -1,6 +0,0 @@
---
source: src/pyflakes/mod.rs
expression: checks
---
[]

View File

@@ -1,6 +0,0 @@
---
source: src/pyflakes/mod.rs
expression: checks
---
[]

View File

@@ -1,6 +0,0 @@
---
source: src/pyflakes/mod.rs
expression: diagnostics
---
[]

View File

@@ -1,6 +0,0 @@
---
source: src/pyflakes/mod.rs
expression: checks
---
[]

View File

@@ -1,6 +0,0 @@
---
source: src/pygrep_hooks/mod.rs
expression: checks
---
[]

View File

@@ -1,6 +0,0 @@
---
source: src/pygrep_hooks/mod.rs
expression: checks
---
[]

View File

@@ -1,6 +0,0 @@
---
source: src/pyupgrade/mod.rs
expression: checks
---
[]

View File

@@ -1,6 +0,0 @@
---
source: src/pyupgrade/mod.rs
expression: checks
---
[]

View File

@@ -1,6 +0,0 @@
---
source: src/pyupgrade/mod.rs
expression: checks
---
[]

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