Compare commits

..

1064 Commits

Author SHA1 Message Date
Charlie Marsh
fde5dbc9aa Bump version to 0.0.273 (#5218) 2023-06-20 14:37:28 -04:00
konstin
b4bd5a5acb Make the release workflow more resilient (#4728)
## Summary

Currently, it is possible to create a tag and then have the release
fail, which is a problem since we can't edit the tag
(https://github.com/charliermarsh/ruff/issues/4468). This change the
release process so that the tag is created inside the release workflow.
This leaves as a failure mode that we have published to pypi but then
creating the tag or GitHub release doesn't work, but in this case we can
restart and the pypi upload is just skipped because we use the skip
existing option.

The release workflow is started by a workflow dispatch with the tag
instead of creating the tag yourself. You can start the release workflow
without a tag to do a dry run which does not publish an artifacts. You
can optionally add a git sha to the workflow run and it will verify that
the release runs on the mentioned commit.

This also adds docs on how to release and a small style improvement for
the maturin integration.

## Test Plan

Testing is hard since we can't do real releases, i've tested a minimized
workflow in a separate dummy repository.
2023-06-20 18:33:09 +00:00
konstin
acb23dce3c Fix subprocess.run on Windows Python 3.7 (#5220)
## Summary

From the [subprocess
docs](https://docs.python.org/3/library/subprocess.html#subprocess.Popen):

> Changed in version 3.6: args parameter accepts a path-like object if
shell is False and a sequence containing path-like objects on POSIX.
>
> Changed in version 3.8: args parameter accepts a path-like object if
shell is False and a sequence containing bytes and path-like objects on
Windows.

We want to support python 3.7 on windows, so we need to convert the
`Path` into a `str`
2023-06-20 13:53:32 -04:00
Charlie Marsh
30734f06fd Support parenthesized expressions when splitting compound assertions (#5219)
## Summary

I'm looking into the Black stability tests, and here's one failing case.

We split `assert a and (b and c)` into:

```python
assert a
assert (b and c)
```

We fail to split `assert (b and c)` due to the parentheses. But Black
then removes then, and when running Ruff again, we get:

```python
assert a
assert b
assert c
```

This PR just enables us to fix to this in one pass.
2023-06-20 13:47:01 -04:00
Charlie Marsh
4547002eb7 Remove defaults from fixtures/pyproject.toml (#5217)
## Summary

These should be encoded in the tests themselves, rather than here. In
fact, I think they're all unused?
2023-06-20 13:16:00 -04:00
Charlie Marsh
310abc769d Move StarImport to its own module (#5186) 2023-06-20 13:12:46 -04:00
Micha Reiser
b369288833 Accept any Into<AnyNodeRef> as Comments arguments (#5205) 2023-06-20 16:49:21 +00:00
Dhruv Manilawala
6f7d3cc798 Add option (-o/--output-file) to write output to a file (#4950)
## Summary

A new CLI option (`-o`/`--output-file`) to write output to a file
instead of stdout.

Major change is to remove the lock acquired on stdout. The argument is
that the output is buffered and thus the lock is acquired only when
writing a block (8kb). As per the benchmark below there is a slight
performance penalty.

Reference:
https://rustmagazine.org/issue-3/javascript-compiler/#printing-is-slow

## Benchmarks

_Output is truncated to only contain useful information:_

Command: `check --isolated --no-cache --select=ALL --show-source
./test-repos/cpython"`

Latest HEAD (361d45f2b2) with and without
the manual lock on stdout:

```console
Benchmark 1: With lock
  Time (mean ± σ):      5.687 s ±  0.075 s    [User: 17.110 s, System: 0.486 s]
  Range (min … max):    5.615 s …  5.860 s    10 runs

Benchmark 2: Without lock
  Time (mean ± σ):      5.719 s ±  0.064 s    [User: 17.095 s, System: 0.491 s]
  Range (min … max):    5.640 s …  5.865 s    10 runs

Summary
  (1) ran 1.01 ± 0.02 times faster than (2)
```

This PR:

```console
Benchmark 1: This PR
  Time (mean ± σ):      5.855 s ±  0.058 s    [User: 17.197 s, System: 0.491 s]
  Range (min … max):    5.786 s …  5.987 s    10 runs
 
Benchmark 2: Latest HEAD with lock
  Time (mean ± σ):      5.645 s ±  0.033 s    [User: 16.922 s, System: 0.495 s]
  Range (min … max):    5.600 s …  5.712 s    10 runs
 
Summary
  (2) ran 1.04 ± 0.01 times faster than (1)
```

## Test Plan

Run all of the commands which gives output with and without the
`--output-file=ruff.out` option:
* `--show-settings`
* `--show-files`
* `--show-fixes`
* `--diff`
* `--select=ALL`
* `--select=All --show-source`
* `--watch` (only stdout allowed)

resolves: #4754
2023-06-20 22:16:49 +05:30
Micha Reiser
d9e59b21cd Add BestFittingMode (#5184)
## Summary
Black supports for layouts when it comes to breaking binary expressions:

```rust
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
enum BinaryLayout {
    /// Put each operand on their own line if either side expands
    Default,

    /// Try to expand the left to make it fit. Add parentheses if the left or right don't fit.
    ///
    ///```python
    /// [
    ///     a,
    ///     b
    /// ] & c
    ///```
    ExpandLeft,

    /// Try to expand the right to make it fix. Add parentheses if the left or right don't fit.
    ///
    /// ```python
    /// a & [
    ///     b,
    ///     c
    /// ]
    /// ```
    ExpandRight,

    /// Both the left and right side can be expanded. Try in the following order:
    /// * expand the right side
    /// * expand the left side
    /// * expand both sides
    ///
    /// to make the expression fit
    ///
    /// ```python
    /// [
    ///     a,
    ///     b
    /// ] & [
    ///     c,
    ///     d
    /// ]
    /// ```
    ExpandRightThenLeft,
}
```

Our current implementation only handles `ExpandRight` and `Default` correctly. `ExpandLeft` turns out to be surprisingly hard. This PR adds a new `BestFittingMode` parameter to `BestFitting` to support `ExpandLeft`.

There are 3 variants that `ExpandLeft` must support:

**Variant 1**: Everything fits on the line (easy)

```python
[a, b] + c
```

**Variant 2**: Left breaks, but right fits on the line. Doesn't need parentheses

```python
[
	a,
	b
] + c
```

**Variant 3**: The left breaks, but there's still not enough space for the right hand side. Parenthesize the whole expression:

```python
(
	[
		a, 
		b
	]
	+ ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
)
```

Solving Variant 1 and 2 on their own is straightforward The printer gives us this behavior by nesting right inside of the group of left:

```
group(&format_args![
	if_group_breaks(&text("(")),
	soft_block_indent(&group(&format_args![
		left, 
		soft_line_break_or_space(), 
		op, 
		space(), 
		group(&right)
	])),
	if_group_breaks(&text(")"))
])
```

The fundamental problem is that the outer group, which adds the parentheses, always breaks if the left side breaks. That means, we end up with

```python
(
	[
		a,
		b
	] + c
)
```

which is not what we want (we only want parentheses if the right side doesn't fit). 

Okay, so nesting groups don't work because of the outer parentheses. Sequencing groups doesn't work because it results in a right-to-left breaking which is the opposite of what we want. 

Could we use best fitting? Almost! 

```
best_fitting![
	// All flat
	format_args![left, space(), op, space(), right],
	// Break left
	format_args!(group(&left).should_expand(true), space(), op, space(), right],
	// Break all
	format_args![
		text("("), 
		block_indent!(&format_args![
			left, 
			hard_line_break(), 
			op,
			space()
			right
		])
	]
]
```

I hope I managed to write this up correctly. The problem is that the printer never reaches the 3rd variant because the second variant always fits:

* The `group(&left).should_expand(true)` changes the group so that all `soft_line_breaks` are turned into hard line breaks. This is necessary because we want to test if the content fits if we break after the `[`. 
* Now, the whole idea of `best_fitting` is that you can pretend that some content fits on the line when it actually does not. The way this works is that the printer **only** tests if all the content of the variant **up to** the first line break fits on the line (we insert that line break by using `should_expand(true))`. The printer doesn't care whether the rest `a\n, b\n ] + c` all fits on (multiple?) lines. 

Why does breaking right work but not breaking the left? The difference is that we can make the decision whether to parenthesis the expression based on the left expression. We can't do this for breaking left because the decision whether to insert parentheses or not would depend on a lookahead: will the right side break. We simply don't know this yet when printing the parentheses (it would work for the right parentheses but not for the left and indent).

What we kind of want here is to tell the printer: Look, what comes here may or may not fit on a single line but we don't care. Simply test that what comes **after** fits on a line. 

This PR adds a new `BestFittingMode` that has a new `AllLines` option that gives us the desired behavior of testing all content and not just up to the first line break. 

## Test Plan

I added a new example to  `BestFitting::with_mode`
2023-06-20 18:16:01 +02:00
Tom Kuson
6929fcc55f Complete flake8-bugbear documentation (#5178)
## Summary

Completes the documentation for the `flake8-bugbear` ruleset. Related to
#2646.

## Test Plan

`python scripts/check_docs_formatted.py`

---------

Co-authored-by: Charlie Marsh <charlie.r.marsh@gmail.com>
2023-06-20 12:10:58 -04:00
Charlie Marsh
7bc33a8d5f Remove identifier lexing in favor of parser ranges (#5195)
## Summary

Now that all identifiers include ranges (#5194), we can remove a ton of
this "custom lexing" code that we have to sketchily extract identifier
ranges from source.

## Test Plan

`cargo test`
2023-06-20 12:07:29 -04:00
Charlie Marsh
6331598511 Upgrade RustPython to access ranged names (#5194)
## Summary

In https://github.com/astral-sh/RustPython-Parser/pull/8, we modified
RustPython to include ranges for any identifiers that aren't
`Expr::Name` (which already has an identifier).

For example, the `e` in `except ValueError as e` was previously
un-ranged. To extract its range, we had to do some lexing of our own.
This change should improve performance and let us remove a bunch of
code.

## Test Plan

`cargo test`
2023-06-20 15:43:38 +00:00
Thomas de Zeeuw
17f1ecd56e Open cache files in parallel (#5120)
## Summary

Open cache files in parallel (again), brings the performance back to be roughly equal to the old implementation.

## Test Plan

Existing tests should keep working.
2023-06-20 17:43:09 +02:00
Dhruv Manilawala
062b6e5c2b Handle trailing newline in Jupyter notebook JSON string (#5202)
## Summary

Handle trailing newline in Jupyter Notebook JSON string similar to how
`black`
does it.

## Test Plan

Add test cases when the JSON string for notebook ends with and without a
newline.

resolves: #5190
2023-06-20 10:19:11 +00:00
David Szotten
773e79b481 basic formatting for ExprDict (#5167) 2023-06-20 09:25:08 +00:00
Logan Hunt
dfb04e679e Small binary size optimization (#5203) 2023-06-20 08:47:01 +02:00
konstin
5c5d2815af Document gitignore (#5191)
This docs-only change adds explanations to all custom .gitignore entries
2023-06-20 08:07:30 +02:00
Charlie Marsh
4cc3cdba16 Use some more wildcard imports in rules (#5201) 2023-06-20 03:21:08 +00:00
Charlie Marsh
a797e05602 Use a consistent argument ordering for Indexer (#5200) 2023-06-20 02:59:51 +00:00
Evan Rittenhouse
62aa77df31 Fix corner case involving terminal backslash after fixing W293 (#5172)
## Summary

Fixes #4404. 

Consider this file:
```python
if True:
    x = 1; \
<space><space><space>
```

The current implementation of W293 removes the 3 spaces on line 2. This
fix changes the file to:
```python
if True:
    x = 1; \
```
A file can't end in a `\`, according to Python's [lexical
analysis](https://docs.python.org/3/reference/lexical_analysis.html), so
subsequent iterations of the autofixer fail (the AST-based ones
specifically, since they depend on a valid syntax tree and get
re-parsed).

This patch examines the line before the line checked in `W293`. If its
first non-whitespace character is a `\`, the patch will extend the
diagnostic's fix range to all whitespace up until the previous line's
*second* non-whitespace character; that is, it deletes all spaces and
potential `\`s up until the next non-whitespace character on the
previous line.

## Test Plan
Ran `cargo run -p ruff_cli -- ~/Downloads/aa.py --fix --select W293,D100
--no-cache` against the above file. This resulted in:
```
/Users/evan/Downloads/aa.py:1:1: D100 Missing docstring in public module
Found 2 errors (1 fixed, 1 remaining).
```
The file's contents, after the fix:
```python
if True:
    x = 1;<space>
```
The `\` was removed, leaving the terminal space. The space should be
handled by `Rule::TrailingWhitespace`, not `BlankLineWithWhitespace`.
2023-06-20 02:57:24 +00:00
Charlie Marsh
64bd955c58 Remove continuations before trailing semicolons (#5199)
## Summary

Closes #4828.
2023-06-20 02:22:32 +00:00
Charlie Marsh
8e06140d1d Remove continuations when deleting statements (#5198)
## Summary

This PR modifies our statement deletion logic to delete any preceding
continuation lines.

For example, given:

```py
x = 1; \
  import os
```

We'll now rewrite to:

```py
x = 1;
```

In addition, the logic can now handle multiple preceding continuations
(which is unlikely, but valid).
2023-06-19 22:04:28 -04:00
Charlie Marsh
015895bcae Move copyright rule to nursery (#5197)
## Summary

I want this to be explicitly opted-into.
2023-06-19 21:41:47 -04:00
Charlie Marsh
36e01ad6eb Upgrade RustPython (#5192)
## Summary

This PR upgrade RustPython to pull in the changes to `Arguments` (zip
defaults with their identifiers) and all the renames to `CmpOp` and
friends.
2023-06-19 21:09:53 +00:00
Charlie Marsh
ddfdc3bb01 Add rule documentation URL to JSON output (#5187)
## Summary

I want to include URLs to the rule documentation in the LSP (the LSP has
a native `code_description` field for this, which, if specified, causes
the source to be rendered as a link to the docs). This PR exposes the
URL to the documentation in the Ruff JSON output.
2023-06-19 21:09:15 +00:00
Dhruv Manilawala
48f4f2d63d Maintain consistency when deserializing to JSON (#5114)
## Summary

Maintain consistency while deserializing Jupyter notebook to JSON. The
following changes were made:

1. Use string array to store the source value as that's the default
(5781720423/nbformat/v4/nbjson.py (L56-L57))
2. Remove unused structs and enums
3. Reorder the keys in alphabetical order as that's the default.
(5781720423/nbformat/v4/nbjson.py (L51))

### Side effect

Removing the `preserve_order` feature means that the order of keys in
JSON output (`--format json`) will be in alphabetical order. This is
because the value is represented using `serde_json::Value` which
internally is a `BTreeMap`, thus sorting it as per the string key. For
posterity if this turns out to be not ideal, then we could define a
struct representing the JSON object and the order of struct fields will
determine the order in the JSON string.

## Test Plan

Add a test case to assert the raw JSON string.
2023-06-19 23:47:56 +05:30
Charlie Marsh
94abf7f088 Rename *Importation structs to *Import (#5185)
## Summary

I find "Importation" a bit awkward, it may not even be grammatically
correct here.
2023-06-19 12:09:10 -04:00
Thomas de Zeeuw
e3c12764f8 Only use a single cache file per Python package (#5117)
## Summary

This changes the caching design from one cache file per source file, to
one cache file per package. This greatly reduces the amount of cache
files that are opened and written, while maintaining roughly the same
(combined) size as bincode is very compact.

Below are some very much not scientific performance tests. It uses
projects/sources to check:

* small.py: single, 31 bytes Python file with 2 errors.
* test.py: single, 43k Python file with 8 errors.
* fastapi: FastAPI repo, 1134 files checked, 0 errors.

Source   | Before # files | After # files | Before size | After size
-------|-------|-------|-------|-------
small.py | 1              | 1             | 20 K        | 20 K
test.py  | 1              | 1             | 60 K        | 60 K
fastapi  | 1134           | 518           | 4.5 M       | 2.3 M

One question that might come up is why fastapi still has 518 cache files
and not 1? That is because this is using the existing package
resolution, which sees examples, docs, etc. as separate from the "main"
source code (in the fastapi directory in the repo). In this future it
might be worth consider switching to a one cache file per repo strategy.

This new design is not perfect and does have a number of known issues.
First, like the old design it doesn't remove the cache for a source file
that has been (re)moved until `ruff clean` is called.

Second, this currently uses a large mutex around the mutation of the
package cache (e.g. inserting result). This could be (or become) a
bottleneck. It's future work to test and improve this (if needed).

Third, currently the packages and opened and stored in a sequential
loop, this could be done parallel. This is also future work.


## Test Plan

Run `ruff check` (with caching enabled) twice on any Python source code
and it should produce the same results.
2023-06-19 17:46:13 +02:00
konstin
b8d378b0a3 Add a script that tests formatter stability on repositories (#5055)
## Summary

We want to ensure that once formatted content stays the same when
formatted again, which is known as formatter stability or formatter
idempotency, and that the formatter prints syntactically valid code. As
our test cases cover only a limited amount of code, this allows checking
entire repositories.

This adds a new subcommand to `ruff_dev` which can be invoked as `cargo
run --bin ruff_dev -- check-formatter-stability <repo>`. While initially
only intended to check stability, it has also found cases where the
formatter printed invalid syntax or panicked.

 ## Test Plan

Running this on cpython is already identifying bugs
(https://github.com/astral-sh/ruff/pull/5089)
2023-06-19 14:13:38 +00:00
konstin
0e028142f4 Explain dangling comments in the formatter (#5170)
This documentation change improves the section on dangling comments in
the formatter.

---------

Co-authored-by: David Szotten <davidszotten@gmail.com>
Co-authored-by: Micha Reiser <micha@reiser.io>
2023-06-19 14:24:45 +02:00
konstin
361d45f2b2 Add cargo dev repeat for profiling (#5144)
## Summary

This adds a new subcommand that can be used as

```shell
cargo build --bin ruff_dev --profile=release-debug
perf record -g -F 999 target/release-debug/ruff_dev repeat --repeat 30 --exit-zero --no-cache path/to/cpython > /dev/null
flamegraph --perfdata perf.data
```

## Test Plan

This is a ruff internal script. I successfully used it to profile
cpython with the instructions above
2023-06-19 11:40:09 +02:00
Charlie Marsh
be11cae619 Fix allowed-ellipsis detection (#5174)
## Summary

We weren't resetting the `allow_ellipsis` flag properly, which
ultimately caused us to treat the semicolon as "unnecessary" rather than
"creating a multi-statement line".

Closes #5154.
2023-06-19 04:19:41 +00:00
Charlie Marsh
2b82caa163 Detect continuations at start-of-file (#5173)
## Summary

Given:

```python
\
import os
```

Deleting `import os` leaves a syntax error: a file can't end in a
continuation. We have code to handle this case, but it failed to pick up
continuations at the _very start_ of a file.

Closes #5156.
2023-06-19 00:09:02 -04:00
Charlie Marsh
a6cf31cc89 Move dead_scopes to deferred.scopes (#5171)
## Summary

This is more consistent with the rest of the `deferred` patterns.
2023-06-18 15:57:38 +00:00
Charlie Marsh
524a2045ba Enable autofix for unconventional imports rule (#5152)
## Summary

We can now automatically rewrite `import pandas` to `import pandas as
pd`, with minimal changes needed.
2023-06-18 15:56:42 +00:00
Charlie Marsh
a0b750f74b Move unconventional import rule to post-binding phase (#5151)
## Summary

This PR moves the "unconventional import alias" rule (which enforces,
e.g., that `pandas` is imported as `pd`) to the "dead scopes" phase,
after the main linter pass. This (1) avoids an allocation since we no
longer need to create the qualified name in the linter pass; and (2)
will allow us to autofix it, since we'll have access to all references.

## Test Plan

`cargo test` -- all changes are to ranges (which are improvements IMO).
2023-06-18 15:23:40 +00:00
Chris Pryer
195b36c429 Format continue statement (#5165)
<!--
Thank you for contributing to Ruff! To help us out with reviewing,
please consider the following:

- Does this pull request include a summary of the change? (See below.)
- Does this pull request include a descriptive title?
- Does this pull request include references to any relevant issues?
-->

## Summary

Format `continue` statement.

## Test Plan

`continue` is used already in some tests, but if a new test is needed I
could add it.

---------

Co-authored-by: konstin <konstin@mailbox.org>
2023-06-18 11:25:59 +00:00
konstin
5c416e4d9b Pre commit without cargo and other pre-PR improvements (#5146)
This tackles three problems:
* pre-commit was slow because it ran cargo commands
* Improve the clarity on what you need to run to get your PR pass on CI
(and make those fast)
* You had to compile and run `cargo dev generate-all` separately, which
was slow

The first change is to remove all cargo commands except running ruff
itself from pre-commit. With `cargo run --bin ruff` already compiled it
takes about 7s on my machine. It would make sense to also use the ruff
pre-commit action here even if we're then lagging a release behind for
checking ruff on ruff.

The contributing guide is now clear about what you need to run:

```shell
cargo clippy --workspace --all-targets --all-features -- -D warnings  # Linting...
RUFF_UPDATE_SCHEMA=1 cargo test  # Testing and updating ruff.schema.json
pre-commit run --all-files  # rust and python formatting, markdown and python linting, etc.
```

Example timings from my machine:

`cargo clippy --workspace --all-targets --all-features -- -D warnings`:
23s
`RUFF_UPDATE_SCHEMA=1 cargo test`: 2min (recompiling), 1min (no code
changes, this is mainly doc tests)
`pre-commit run --all-files`: 7s

The exact numbers don't matter so much as the approximate experience (6s
is easier to just wait than 1min, esp if you need to fix and rerun). The
biggest remaining block seems to be doc tests, i'm surprised i didn't
find any solution to speeding them up (nextest simply doesn't run them
at all). Also note that the formatter has it's own tests which are much
faster since they avoid linking ruff (`cargo test
ruff_python_formatter`).

The third change is to enable `cargo test` to update the schema. Similar
to `INSTA_UPDATE=always`, i've added `RUFF_UPDATE_SCHEMA=1` (name open
to bikeshedding), so `RUFF_UPDATE_SCHEMA=1 cargo test` updates the
schema, while `cargo test` still fails as expected if the repo isn't
up-to-date.

---------

Co-authored-by: Dhruv Manilawala <dhruvmanila@gmail.com>
2023-06-18 11:00:42 +00:00
konstin
763d38cafb Refactor top llvm-lines entry (#5147)
## Summary

This refactors the top entry in terms of llvm lines,
`RuleCodePrefix::iter()`. It's only used for generating the schema and
the clap completion so no effect on performance.

I've confirmed with
```
CARGO_TARGET_DIR=target-llvm-lines RUSTFLAGS="-Csymbol-mangling-version=v0" cargo llvm-lines -p ruff --lib | head -n 20
```
that this indeed remove the method from the list of heaviest symbols in
terms of llvm-lines

Before:
```
  Lines                  Copies               Function name
  -----                  ------               -------------
  1768469                40538                (TOTAL)
    10391 (0.6%,  0.6%)      1 (0.0%,  0.0%)  <ruff[fa0f2e8ef07114da]::codes::RuleCodePrefix>::iter
     8250 (0.5%,  1.1%)      1 (0.0%,  0.0%)  <ruff[fa0f2e8ef07114da]::codes::Rule>::noqa_code
     7427 (0.4%,  1.5%)      1 (0.0%,  0.0%)  <ruff[fa0f2e8ef07114da]::checkers::ast::Checker as ruff_python_ast[c4c9eadfa5741dd4]::visitor::Visitor>::visit_stmt
     6536 (0.4%,  1.8%)      1 (0.0%,  0.0%)  <<ruff[fa0f2e8ef07114da]::settings::options::Options as serde[1a28808d63625aed]::de::Deserialize>::deserialize::__Visitor as serde[1a28808d63625aed]::de::Visitor>::visit_map::<toml_edit[de4ca26332d39787]::de::spanned::SpannedDeserializer<toml_edit[de4ca26332d39787]::de::value::ValueDeserializer>>
     6536 (0.4%,  2.2%)      1 (0.0%,  0.0%)  <<ruff[fa0f2e8ef07114da]::settings::options::Options as serde[1a28808d63625aed]::de::Deserialize>::deserialize::__Visitor as serde[1a28808d63625aed]::de::Visitor>::visit_map::<toml_edit[de4ca26332d39787]::de::table::TableMapAccess>
     6533 (0.4%,  2.6%)      1 (0.0%,  0.0%)  <<ruff[fa0f2e8ef07114da]::settings::options::Options as serde[1a28808d63625aed]::de::Deserialize>::deserialize::__Visitor as serde[1a28808d63625aed]::de::Visitor>::visit_map::<toml_edit[de4ca26332d39787]::de::datetime::DatetimeDeserializer>
     5727 (0.3%,  2.9%)      1 (0.0%,  0.0%)  <ruff[fa0f2e8ef07114da]::checkers::ast::Checker as ruff_python_ast[c4c9eadfa5741dd4]::visitor::Visitor>::visit_expr
     4453 (0.3%,  3.2%)      1 (0.0%,  0.0%)  ruff[fa0f2e8ef07114da]::flake8_to_ruff::converter::convert
     3790 (0.2%,  3.4%)      1 (0.0%,  0.0%)  <&ruff[fa0f2e8ef07114da]::registry::Linter as core[da82827a87f140f9]::iter::traits::collect::IntoIterator>::into_iter
     3416 (0.2%,  3.6%)      1 (0.0%,  0.0%)  <ruff[fa0f2e8ef07114da]::registry::Linter>::code_for_rule
     3187 (0.2%,  3.7%)      1 (0.0%,  0.0%)  <ruff[fa0f2e8ef07114da]::codes::Rule as core[da82827a87f140f9]::fmt::Debug>::fmt
     3185 (0.2%,  3.9%)      1 (0.0%,  0.0%)  <&str as core[da82827a87f140f9]::convert::From<&ruff[fa0f2e8ef07114da]::codes::Rule>>::from
     3185 (0.2%,  4.1%)      1 (0.0%,  0.0%)  <&str as core[da82827a87f140f9]::convert::From<ruff[fa0f2e8ef07114da]::codes::Rule>>::from
     3185 (0.2%,  4.3%)      1 (0.0%,  0.0%)  <ruff[fa0f2e8ef07114da]::codes::Rule as core[da82827a87f140f9]::convert::AsRef<str>>::as_ref
     3183 (0.2%,  4.5%)      1 (0.0%,  0.0%)  <ruff[fa0f2e8ef07114da]::codes::RuleIter>::get
     2718 (0.2%,  4.6%)      1 (0.0%,  0.0%)  <<ruff[fa0f2e8ef07114da]::settings::options::Options as serde[1a28808d63625aed]::de::Deserialize>::deserialize::__Visitor as serde[1a28808d63625aed]::de::Visitor>::visit_seq::<toml_edit[de4ca26332d39787]::de::array::ArraySeqAccess>
     2706 (0.2%,  4.8%)      1 (0.0%,  0.0%)  <&ruff[fa0f2e8ef07114da]::codes::Pylint as core[da82827a87f140f9]::iter::traits::collect::IntoIterator>::into_iter
```
After:
```
  Lines                  Copies               Function name
  -----                  ------               -------------
  1763380                40806                (TOTAL)
     8250 (0.5%,  0.5%)      1 (0.0%,  0.0%)  <ruff[fa0f2e8ef07114da]::codes::Rule>::noqa_code
     7427 (0.4%,  0.9%)      1 (0.0%,  0.0%)  <ruff[fa0f2e8ef07114da]::checkers::ast::Checker as ruff_python_ast[c4c9eadfa5741dd4]::visitor::Visitor>::visit_stmt
     6536 (0.4%,  1.3%)      1 (0.0%,  0.0%)  <<ruff[fa0f2e8ef07114da]::settings::options::Options as serde[1a28808d63625aed]::de::Deserialize>::deserialize::__Visitor as serde[1a28808d63625aed]::de::Visitor>::visit_map::<toml_edit[de4ca26332d39787]::de::spanned::SpannedDeserializer<toml_edit[de4ca26332d39787]::de::value::ValueDeserializer>>
     6536 (0.4%,  1.6%)      1 (0.0%,  0.0%)  <<ruff[fa0f2e8ef07114da]::settings::options::Options as serde[1a28808d63625aed]::de::Deserialize>::deserialize::__Visitor as serde[1a28808d63625aed]::de::Visitor>::visit_map::<toml_edit[de4ca26332d39787]::de::table::TableMapAccess>
     6533 (0.4%,  2.0%)      1 (0.0%,  0.0%)  <<ruff[fa0f2e8ef07114da]::settings::options::Options as serde[1a28808d63625aed]::de::Deserialize>::deserialize::__Visitor as serde[1a28808d63625aed]::de::Visitor>::visit_map::<toml_edit[de4ca26332d39787]::de::datetime::DatetimeDeserializer>
     5727 (0.3%,  2.3%)      1 (0.0%,  0.0%)  <ruff[fa0f2e8ef07114da]::checkers::ast::Checker as ruff_python_ast[c4c9eadfa5741dd4]::visitor::Visitor>::visit_expr
     4453 (0.3%,  2.6%)      1 (0.0%,  0.0%)  ruff[fa0f2e8ef07114da]::flake8_to_ruff::converter::convert
     3790 (0.2%,  2.8%)      1 (0.0%,  0.0%)  <&ruff[fa0f2e8ef07114da]::registry::Linter as core[da82827a87f140f9]::iter::traits::collect::IntoIterator>::into_iter
     3416 (0.2%,  3.0%)      1 (0.0%,  0.0%)  <ruff[fa0f2e8ef07114da]::registry::Linter>::code_for_rule
     3187 (0.2%,  3.2%)      1 (0.0%,  0.0%)  <ruff[fa0f2e8ef07114da]::codes::Rule as core[da82827a87f140f9]::fmt::Debug>::fmt
     3185 (0.2%,  3.3%)      1 (0.0%,  0.0%)  <&str as core[da82827a87f140f9]::convert::From<&ruff[fa0f2e8ef07114da]::codes::Rule>>::from
     3185 (0.2%,  3.5%)      1 (0.0%,  0.0%)  <&str as core[da82827a87f140f9]::convert::From<ruff[fa0f2e8ef07114da]::codes::Rule>>::from
     3185 (0.2%,  3.7%)      1 (0.0%,  0.0%)  <ruff[fa0f2e8ef07114da]::codes::Rule as core[da82827a87f140f9]::convert::AsRef<str>>::as_ref
     3183 (0.2%,  3.9%)      1 (0.0%,  0.0%)  <ruff[fa0f2e8ef07114da]::codes::RuleIter>::get
     2718 (0.2%,  4.0%)      1 (0.0%,  0.0%)  <<ruff[fa0f2e8ef07114da]::settings::options::Options as serde[1a28808d63625aed]::de::Deserialize>::deserialize::__Visitor as serde[1a28808d63625aed]::de::Visitor>::visit_seq::<toml_edit[de4ca26332d39787]::de::array::ArraySeqAccess>
     2706 (0.2%,  4.2%)      1 (0.0%,  0.0%)  <&ruff[fa0f2e8ef07114da]::codes::Pylint as core[da82827a87f140f9]::iter::traits::collect::IntoIterator>::into_iter
     2573 (0.1%,  4.3%)      1 (0.0%,  0.0%)  <<ruff[fa0f2e8ef07114da]::rules::isort::settings::Options as serde[1a28808d63625aed]::de::Deserialize>::deserialize::__Visitor as serde[1a28808d63625aed]::de::Visitor>::visit_map::<toml_edit[de4ca26332d39787]::de::spanned::SpannedDeserializer<toml_edit[de4ca26332d39787]::de::value::ValueDeserializer>>
```
I didn't measure the effect on binary size this time.

## Testing

`cargo test` which uses this to generate the schema didn't change
2023-06-18 12:39:06 +02:00
Evan Rittenhouse
653a0ebf2d Add Applicability to pyupgrade (#5162)
## Summary

Fixes some of #4184.
2023-06-17 19:33:11 +00:00
Evan Rittenhouse
95448ba669 Add Applicability to isort (#5161)
## Summary

Fixes some of #4184.
2023-06-17 19:08:11 +00:00
Charlie Marsh
f18e10183f Add some minor tweaks to latest docs (#5164) 2023-06-17 17:04:50 +00:00
Tom Kuson
98920909c6 Complete documentation for flake8-blind-except and flake8-raise rules (#5143)
## Summary

Completes the documentation for the `flake8-blind-except` and
`flake8-raise` rules.

Related to #2646.

## Test Plan

`python scripts/check_docs_formatted.py`
2023-06-17 12:56:27 -04:00
Evan Rittenhouse
e1e1d2d341 Add Applicability to flynt (#5160)
## Summary

Fixes some of #4184.
2023-06-17 12:05:43 -04:00
David Szotten
4b9b6829dc format StmtBreak (#5158)
## Summary

format `StmtBreak`

trying to learn how to help out with the formatter. starting simple

## Test Plan

new snapshot test
2023-06-17 10:31:29 +02:00
Charlie Marsh
be107dad64 Add a PNG variant of the Astral badge (#5155) 2023-06-17 03:24:32 +00:00
Charlie Marsh
d0ad1ed0af Replace static CallPath vectors with matches! macros (#5148)
## Summary

After #5140, I audited the codebase for similar patterns (defining a
list of `CallPath` entities in a static vector, then looping over them
to pattern-match). This PR migrates all other such cases to use `match`
and `matches!` where possible.

There are a few benefits to this:

1. It more clearly denotes the intended semantics (branches are
exclusive).
2. The compiler can help deduplicate the patterns and detect unreachable
branches.
3. Performance: in the benchmark below, the all-rules performance is
increased by nearly 10%...

## Benchmarks

I decided to benchmark against a large file in the Airflow repository
with a lot of type annotations
([`views.py`](https://raw.githubusercontent.com/apache/airflow/f03f73100e8a7d6019249889de567cb00e71e457/airflow/www/views.py)):

```
linter/default-rules/airflow/views.py
                        time:   [10.871 ms 10.882 ms 10.894 ms]
                        thrpt:  [19.739 MiB/s 19.761 MiB/s 19.781 MiB/s]
                 change:
                        time:   [-2.7182% -2.5687% -2.4204%] (p = 0.00 < 0.05)
                        thrpt:  [+2.4805% +2.6364% +2.7942%]
                        Performance has improved.

linter/all-rules/airflow/views.py
                        time:   [24.021 ms 24.038 ms 24.062 ms]
                        thrpt:  [8.9373 MiB/s 8.9461 MiB/s 8.9527 MiB/s]
                 change:
                        time:   [-8.9537% -8.8516% -8.7527%] (p = 0.00 < 0.05)
                        thrpt:  [+9.5923% +9.7112% +9.8342%]
                        Performance has improved.
Found 12 outliers among 100 measurements (12.00%)
  5 (5.00%) high mild
  7 (7.00%) high severe
```

The impact is dramatic -- nearly a 10% improvement for `all-rules`.
2023-06-16 17:34:42 +00:00
Charlie Marsh
b3240dbfa2 Avoid propagating BindingKind::Global and BindingKind::Nonlocal (#5136)
## Summary

This PR fixes a small quirk in the semantic model. Typically, when we
see an import, like `import foo`, we create a `BindingKind::Importation`
for it. However, if `foo` has been declared as a `global`, then we
propagate the kind forward. So given:

```python
global foo

import foo
```

We'd create two bindings for `foo`, both with type `global`.

This was originally borrowed from Pyflakes, and it exists to help avoid
false-positives like:

```python
def f():
    global foo

    # Don't mark `foo` as "assigned but unused"! It's a global!
    foo = 1
```

This PR removes that behavior, and instead tracks "Does this binding
refer to a global?" as a flag. This is much cleaner, since it means we
don't "lose" the identity of various bindings.

As a very strange example of why this matters, consider:

```python
def foo():
    global Member

    from module import Member

    x: Member = 1
```

`Member` is only used in a typing context, so we should flag it and say
"move it to a `TYPE_CHECKING` block". However, when we go to analyze
`from module import Member`, it has `BindingKind::Global`. So we don't
even know that it's an import!
2023-06-16 11:06:59 -04:00
Charlie Marsh
fd1dfc3bfa Add support for global and nonlocal symbol renames (#5134)
## Summary

In #5074, we introduced an abstraction to support local symbol renames
("local" here refers to "within a module"). However, that abstraction
didn't support `global` and `nonlocal` symbols. This PR extends it to
those cases.

Broadly, there are considerations.

First, if we're renaming a symbol in a scope in which it is declared
`global` or `nonlocal`. For example, given:

```python
x = 1

def foo():
    global x
```

Then when renaming `x` in `foo`, we need to detect that it's `global`
and instead perform the rename starting from the module scope.

Second, when renaming a symbol, we need to determine the scopes in which
it is declared `global` or `nonlocal`. This is effectively the inverse
of the above: when renaming `x` in the module scope, we need to detect
that we should _also_ rename `x` in `foo`.

To support these cases, the renaming algorithm was adjusted as follows:

- When we start a rename in a scope, determine whether the symbol is
declared `global` or `nonlocal` by looking for a `global` or `nonlocal`
binding. If it is, start the rename in the defining scope. (This
requires storing the defining scope on the `nonlocal` binding, which is
new.)
- We then perform the rename in the defining scope.
- We then check whether the symbol was declared as `global` or
`nonlocal` in any scopes, and perform the rename in those scopes too.
(Thankfully, this doesn't need to be done recursively.)

Closes #5092.

## Test Plan

Added some additional snapshot tests.
2023-06-16 14:35:10 +00:00
Charlie Marsh
b9754bd5c5 Add autofix for Set-to-AbstractSet rewrite using reference tracking (#5074)
## Summary

This PR enables autofix behavior for the `flake8-pyi` rule that asks you
to alias `Set` to `AbstractSet` when importing `collections.abc.Set`.
It's not the most important rule, but it's a good isolated test-case for
local symbol renaming.

The renaming algorithm is outlined in-detail in the `renamer.rs` module.
But to demonstrate the behavior, here's the diff when running this fix
over a complex file that exercises a few edge cases:

```diff
--- a/foo.pyi
+++ b/foo.pyi
@@ -1,16 +1,16 @@
 if True:
-    from collections.abc import Set
+    from collections.abc import Set as AbstractSet
 else:
-    Set = 1
+    AbstractSet = 1

-x: Set = set()
+x: AbstractSet = set()

-x: Set
+x: AbstractSet

-del Set
+del AbstractSet

 def f():
-    print(Set)
+    print(AbstractSet)

     def Set():
         pass
```

Making this work required resolving a bunch of edge cases in the
semantic model that were causing us to "lose track" of references. For
example, the above wasn't possible with our previous approach to
handling deletions (#5071). Similarly, the `x: Set` "delayed annotation"
tracking was enabled via #5070. And many of these edits would've failed
if we hadn't changed `BindingKind` to always match the identifier range
(#5090). So it's really the culmination of a bunch of changes over the
course of the week.

The main outstanding TODO is that this doesn't support `global` or
`nonlocal` usages. I'm going to take a look at that tonight, but I'm
comfortable merging this as-is.

Closes #1106.

Closes #5091.
2023-06-16 14:12:33 +00:00
Charlie Marsh
307f7a735c Avoid allocations in lowercase comparisons (#5137)
## Summary

I noticed that we have a few hot comparisons that involve called
`s.to_lowercase()`. We can avoid an allocation by comparing characters
directly.
2023-06-16 08:57:43 -04:00
Charlie Marsh
3af9dfeb0a Rewrite suspicious_function_call as a match statement (#5140)
## Summary

@konstin mentioned that in profiling, this function accounted for a
non-trivial amount of time (0.33% of total execution, the most of any
rule). This PR attempts to rewrite it as a match statement for better
performance over a looping comparison.

## Test Plan

`cargo test`
2023-06-16 08:57:20 -04:00
Charlie Marsh
5526699535 Use const-singleton helpers in more rules (#5142) 2023-06-16 04:28:35 +00:00
Charlie Marsh
fab2a4adf7 Use matches! for insecure hash rule (#5141) 2023-06-16 04:18:32 +00:00
Charlie Marsh
13813dc1b1 Skip DJ008 enforcement in stub files (#5139)
Closes #5138.
2023-06-16 03:49:40 +00:00
Charlie Marsh
70c01257ca Minor formatting changes to Checker (#5135) 2023-06-15 22:42:21 -04:00
Evan Rittenhouse
26d19655db Add Applicability to flake8_tidy_imports (#5131)
## Summary
Fixes some of https://github.com/astral-sh/ruff/issues/4184
2023-06-15 18:09:00 -04:00
Charlie Marsh
1f856aa576 Don't treat straight imports of __future__ as __future__ imports (#5128)
## Summary

If you `import __future__`, it's not subject to the same rules as `from
__future__ import feature` -- i.e., this is fine:

```python
x = 1

import __future__
```

It doesn't really make sense to treat these as `__future__` imports
(though I can't imagine anyone ever does this anyway).
2023-06-15 20:53:02 +00:00
Evan Rittenhouse
1e383483f7 Add Applicability to flake8_quotes fixes (#5130)
## Summary

Fixes some of #4184
2023-06-15 16:50:54 -04:00
Evan Rittenhouse
89b328c6be Add Applicability to flake8_logging_format fixes (#5129)
## Summary

Fixes some of #4184
2023-06-15 16:50:19 -04:00
Evan Rittenhouse
6143065fc2 Add Applicability to flake8_comma fixes (#5127)
## Summary

Fixes some of #4184
2023-06-15 16:49:54 -04:00
Charlie Marsh
107a295af4 Allow async with in redefined-loop-name (#5125)
## Summary

Closes #5124.
2023-06-15 15:00:19 -04:00
konstin
c811213302 Allow space in filename for powershell + windows + python module (#5115)
Fixes #5077

## Summary

Previously, in a powershell on windows when using `python -m ruff`
instead of `ruff` a call such as `python -m ruff "a b.py"` would fail
because the space would be split into two arguments.

The python docs
[recommend](https://docs.python.org/3/library/os.html#os.spawnv) using
subprocess instead of os.spawn variants, which does fix the problem.

## Test Plan

I manually confirmed that the problem previously occurred and now
doesn't anymore. This only happens in a very specific environment
(maturin build, windows, powershell), so i could try adding a step on CI
for it but i don't think it's worth it.

```
(.venv) PS C:\Users\Konstantin\PycharmProjects\ruff> python -m ruff "a b.py"
warning: Detected debug build without --no-cache.
error: Failed to lint a: The system cannot find the file specified. (os error 2)
error: Failed to lint b.py: The system cannot find the file specified. (os error 2)
a:1:1: E902 The system cannot find the file specified. (os error 2)
b.py:1:1: E902 The system cannot find the file specified. (os error 2)
Found 2 errors.
(.venv) PS C:\Users\Konstantin\PycharmProjects\ruff> python -m ruff "a b.py"
warning: Detected debug build without --no-cache.
a b.py:2:5: F841 [*] Local variable `x` is assigned to but never used
Found 1 error.
[*] 1 potentially fixable with the --fix option.
```
2023-06-15 20:57:00 +02:00
Charlie Marsh
5ea3e42513 Always use identifier ranges to store bindings (#5110)
## Summary

At present, when we store a binding, we include a `TextRange` alongside
it. The `TextRange` _sometimes_ matches the exact range of the
identifier to which the `Binding` is linked, but... not always.

For example, given:

```python
x = 1
```

The binding we create _will_ use the range of `x`, because the left-hand
side is an `Expr::Name`, which has a valid range on it.

However, given:

```python
try:
  pass
except ValueError as e:
  pass
```

When we create a binding for `e`, we don't have a `TextRange`... The AST
doesn't give us one. So we end up extracting it via lexing.

This PR extends that pattern to the rest of the binding kinds, to ensure
that whenever we create a binding, we always use the range of the bound
name. This leads to better diagnostics in cases like pattern matching,
whereby the diagnostic for "unused variable `x`" here used to include
`*x`, instead of just `x`:

```python
def f(provided: int) -> int:
    match provided:
        case [_, *x]:
            pass
```

This is _also_ required for symbol renames, since we track writes as
bindings -- so we need to know the ranges of the bound symbols.

By storing these bindings precisely, we can also remove the
`binding.trimmed_range` abstraction -- since bindings already use the
"trimmed range".

To implement this behavior, I took some of our existing utilities (like
the code we had for `except ValueError as e` above), migrated them from
a full lexer to a zero-allocation lexer that _only_ identifies
"identifiers", and moved the behavior into a trait, so we can now do
`stmt.identifier(locator)` to get the range for the identifier.

Honestly, we might end up discarding much of this if we decide to put
ranges on all identifiers
(https://github.com/astral-sh/RustPython-Parser/pull/8). But even if we
do, this will _still_ be a good change, because the lexer introduced
here is useful beyond names (e.g., we use it find the `except` keyword
in an exception handler, to find the `else` after a `for` loop, and so
on). So, I'm fine committing this even if we end up changing our minds
about the right approach.

Closes #5090.

## Benchmarks

No significant change, with one statistically significant improvement
(-2.1654% on `linter/all-rules/large/dataset.py`):

```
linter/default-rules/numpy/globals.py
                        time:   [73.922 µs 73.955 µs 73.986 µs]
                        thrpt:  [39.882 MiB/s 39.898 MiB/s 39.916 MiB/s]
                 change:
                        time:   [-0.5579% -0.4732% -0.3980%] (p = 0.00 < 0.05)
                        thrpt:  [+0.3996% +0.4755% +0.5611%]
                        Change within noise threshold.
Found 6 outliers among 100 measurements (6.00%)
  4 (4.00%) low severe
  1 (1.00%) low mild
  1 (1.00%) high mild
linter/default-rules/pydantic/types.py
                        time:   [1.4909 ms 1.4917 ms 1.4926 ms]
                        thrpt:  [17.087 MiB/s 17.096 MiB/s 17.106 MiB/s]
                 change:
                        time:   [+0.2140% +0.2741% +0.3392%] (p = 0.00 < 0.05)
                        thrpt:  [-0.3380% -0.2734% -0.2136%]
                        Change within noise threshold.
Found 4 outliers among 100 measurements (4.00%)
  3 (3.00%) high mild
  1 (1.00%) high severe
linter/default-rules/numpy/ctypeslib.py
                        time:   [688.97 µs 691.34 µs 694.15 µs]
                        thrpt:  [23.988 MiB/s 24.085 MiB/s 24.168 MiB/s]
                 change:
                        time:   [-1.3282% -0.7298% -0.1466%] (p = 0.02 < 0.05)
                        thrpt:  [+0.1468% +0.7351% +1.3461%]
                        Change within noise threshold.
Found 15 outliers among 100 measurements (15.00%)
  1 (1.00%) low mild
  2 (2.00%) high mild
  12 (12.00%) high severe
linter/default-rules/large/dataset.py
                        time:   [3.3872 ms 3.4032 ms 3.4191 ms]
                        thrpt:  [11.899 MiB/s 11.954 MiB/s 12.011 MiB/s]
                 change:
                        time:   [-0.6427% -0.2635% +0.0906%] (p = 0.17 > 0.05)
                        thrpt:  [-0.0905% +0.2642% +0.6469%]
                        No change in performance detected.
Found 20 outliers among 100 measurements (20.00%)
  1 (1.00%) low severe
  2 (2.00%) low mild
  4 (4.00%) high mild
  13 (13.00%) high severe

linter/all-rules/numpy/globals.py
                        time:   [148.99 µs 149.21 µs 149.42 µs]
                        thrpt:  [19.748 MiB/s 19.776 MiB/s 19.805 MiB/s]
                 change:
                        time:   [-0.7340% -0.5068% -0.2778%] (p = 0.00 < 0.05)
                        thrpt:  [+0.2785% +0.5094% +0.7395%]
                        Change within noise threshold.
Found 2 outliers among 100 measurements (2.00%)
  1 (1.00%) low mild
  1 (1.00%) high severe
linter/all-rules/pydantic/types.py
                        time:   [3.0362 ms 3.0396 ms 3.0441 ms]
                        thrpt:  [8.3779 MiB/s 8.3903 MiB/s 8.3997 MiB/s]
                 change:
                        time:   [-0.0957% +0.0618% +0.2125%] (p = 0.45 > 0.05)
                        thrpt:  [-0.2121% -0.0618% +0.0958%]
                        No change in performance detected.
Found 11 outliers among 100 measurements (11.00%)
  1 (1.00%) low severe
  3 (3.00%) low mild
  5 (5.00%) high mild
  2 (2.00%) high severe
linter/all-rules/numpy/ctypeslib.py
                        time:   [1.6879 ms 1.6894 ms 1.6909 ms]
                        thrpt:  [9.8478 MiB/s 9.8562 MiB/s 9.8652 MiB/s]
                 change:
                        time:   [-0.2279% -0.0888% +0.0436%] (p = 0.18 > 0.05)
                        thrpt:  [-0.0435% +0.0889% +0.2284%]
                        No change in performance detected.
Found 5 outliers among 100 measurements (5.00%)
  4 (4.00%) low mild
  1 (1.00%) high severe
linter/all-rules/large/dataset.py
                        time:   [7.1520 ms 7.1586 ms 7.1654 ms]
                        thrpt:  [5.6777 MiB/s 5.6831 MiB/s 5.6883 MiB/s]
                 change:
                        time:   [-2.5626% -2.1654% -1.7780%] (p = 0.00 < 0.05)
                        thrpt:  [+1.8102% +2.2133% +2.6300%]
                        Performance has improved.
Found 2 outliers among 100 measurements (2.00%)
  1 (1.00%) low mild
  1 (1.00%) high mild
```
2023-06-15 18:43:19 +00:00
konstin
66089e1a2e Fix a number of formatter errors from the cpython repository (#5089)
## Summary

This fixes a number of problems in the formatter that showed up with
various files in the [cpython](https://github.com/python/cpython)
repository. These problems surfaced as unstable formatting and invalid
code. This is not the entirety of problems discovered through cpython,
but a big enough chunk to separate it. Individual fixes are generally
individual commits. They were discovered with #5055, which i update as i
work through the output

## Test Plan

I added regression tests with links to cpython for each entry, except
for the two stubs that also got comment stubs since they'll be
implemented properly later.
2023-06-15 11:24:14 +00:00
Dhruv Manilawala
097823b56d Ability to perform integration test on Jupyter notebooks (#5076)
## Summary

Ability to perform integration test on Jupyter notebooks

Part of #1218

## Test Plan

`cargo test`
2023-06-15 08:04:27 +05:30
Charlie Marsh
ed8113267c Add autofix specification levels for a variety of rules (#5109) 2023-06-14 22:03:37 -04:00
Charlie Marsh
c654280d84 Use direct links for all PEP 8 references (#5108) 2023-06-14 21:12:23 -04:00
Charlie Marsh
99486b38f4 Disambiguate all Python documentation references (#5107) 2023-06-15 00:47:00 +00:00
Charlie Marsh
716cab2f19 Run rustfmt on nightly to clean up erroneous comments (#5106)
## Summary

This PR runs `rustfmt` with a few nightly options as a one-time fix to
catch some malformatted comments. I ended up just running with:

```toml
condense_wildcard_suffixes = true
edition = "2021"
max_width = 100
normalize_comments = true
normalize_doc_attributes = true
reorder_impl_items = true
unstable_features = true
use_field_init_shorthand = true
```

Since these all seem like reasonable things to fix, so may as well while
I'm here.
2023-06-15 00:19:05 +00:00
Charlie Marsh
9ab16fb417 Add target-version link to relevant rules (#5105) 2023-06-15 00:12:32 +00:00
Charlie Marsh
458beccf14 Uniformly put ## Options at the end of documentation (#5104) 2023-06-15 00:04:51 +00:00
Tom Kuson
ccbc863960 Complete pyupgrade documentation (#5096)
## Summary

Completes the documentation for the `pyupgrade` rules.

Related to #2646.

## Test Plan

`python scripts/check_docs_formatted.py`
2023-06-14 23:43:12 +00:00
Charlie Marsh
71b3130ff1 Remove manual await detection (#5103)
We can just use `any_over_expr` instead.
2023-06-14 22:17:14 +00:00
Tom Kuson
08cd140ea6 Ignore reimplemented-builtin if in async context (#5101)
## Summary

Checks if `checker` is in an `async` context. If yes, return early.

Fixes #5098.

## Test Plan

`cargo test`
2023-06-14 18:00:30 -04:00
Charlie Marsh
848f184b8c Enable UTC-import for datetime-utc-alias fix (#5100)
## Summary

Small update to leverage `get_or_import_symbol` to fix `UP017` in more
cases (e.g., when we need to import `UTC`, or access it from an alias or
something).

## Test Plan

Check out the updated snapshot.
2023-06-14 21:13:36 +00:00
Charlie Marsh
56476dfd61 Use matches! for CallPath comparisons (#5099)
## Summary

This PR consistently uses `matches! for static `CallPath` comparisons.
In some cases, we can significantly reduce the number of cases or
checks.

## Test Plan

`cargo test `
2023-06-14 17:06:34 -04:00
Charlie Marsh
bae183b823 Rename semantic_model and model usages to semantic (#5097)
## Summary

As discussed in Discord, and similar to oxc, we're going to refer to
this as `.semantic()` everywhere.

While I was auditing usages of `model: &SemanticModel`, I also changed
as many function signatures as I could find to consistently take the
model as the _last_ argument, rather than the first.
2023-06-14 15:01:51 -04:00
Charlie Marsh
65dbfd2556 Improve names and documentation on scope API (#5095)
## Summary

Just minor improvements to improve consistency of method names and
availability.
2023-06-14 18:28:55 +00:00
Charlie Marsh
86ff1febea Re-export ruff_python_semantic members (#5094)
## Summary

This PR adds a more unified public API to `ruff_python_semantic`, so
that we don't need to do deeply nested imports all over the place.
2023-06-14 18:23:38 +00:00
Charlie Marsh
a33bbe6335 Track "delayed" annotations in the semantic model (#5070)
## Summary

This PR tackles a corner case that we'll need to support local symbol
renaming. It relates to a nuance in how we want handle annotations
(i.e., `AnnAssign` statements with no value, like `x: int` in a function
body).

When we see a statement like:

```python
x: int
```

We create a `BindingKind::Annotation` for `x`. This is a special
`BindingKind` that the resolver isn't allowed to return. For example,
given:

```python
x: int
print(x)
```

The second line will yield an `undefined-name` error.

So why does this `BindingKind` exist at all? In Pyflakes, to support the
`unused-annotation` lint:

```python
def f():
    x: int  # unused-annotation
```

If we don't track `BindingKind::Annotation`, we can't lint for unused
variables that are only "defined" via annotations.

There are a few other wrinkles to `BindingKind::Annotation`. One is
that, if a binding already exists in the scope, we actually just discard
the `BindingKind`. So in this case:

```python
x = 1
x: int
```

When we go to create the `BindingKind::Annotation` for the second
statement, we notice that (1) we're creating an annotation but (2) the
scope already has binding for the name -- so we just drop the binding on
the floor. This has the nice property that annotations aren't considered
to "shadow" another binding, which is important in a bunch of places
(e.g., if we have `import os; os: int`, we still consider `os` to be an
import, as we should). But it also means that these "delayed"
annotations are one of the few remaining references that we don't track
anywhere in the semantic model.

This PR adds explicit support for these via a new `delayed_annotations`
attribute on the semantic model. These should be extremely rare, but we
do need to track them if we want to support local symbol renaming.

### This isn't the right way to model this

This isn't the right way to model this.

Here's an alternative:

- Remove `BindingKind::Annotation`, and treat annotations as their own,
separate concept.
- Instead of storing a map from name to `BindingId` on each `Scope`,
store a map from name to... `SymbolId`.
- Introduce a `Symbol` abstraction, where a symbol can point to a
current binding, and a list of annotations, like:

```rust
pub struct Symbol {
  binding: Option<BindingId>,
  annotations: Vec<AnnotationId>
}
```

If we did this, we could appropriately model the semantics described
above. When we go to resolve a binding, we ignore annotations (always).
When we try to find unused variables, we look through the list of
symbols, and have sufficient information to discriminate between
annotations and bound variables. Etc.

The main downside of this `Symbol`-based approach is that it's going to
take a lot more work to implement, and it'll be less performant (we'll
be storing more data per symbol, and our binding lookups will have an
added layer of indirection).
2023-06-14 17:54:35 +00:00
Charlie Marsh
c992cfa76e Make some of ruff_python_semantic pub(crate) (#5093) 2023-06-14 17:49:37 +00:00
konstin
916f0889f8 Add pyproject.toml to include option doc (#5080)
Fixes an oversight where i didn't update this initially
2023-06-14 15:55:12 +00:00
MT BENTERKI
c1fd2c8a8e Update tutorial doc typo (#5088) 2023-06-14 11:17:35 -04:00
Charlie Marsh
732b0405d7 Remove FixMode::None (#5087)
## Summary

We now _always_ generate fixes, so `FixMode::None` and
`FixMode::Generate` are redundant. We can also remove the TODO around
`--fix-dry-run`, since that's our default behavior.

Closes #5081.
2023-06-14 11:17:09 -04:00
Thomas de Zeeuw
e7316c1cc6 Consider ignore-names in all pep8 naming rules (#5079)
## Summary

This changes all remaining pep8 naming rules to consider the
`ingore-names` argument.

Closes #5050

## Test Plan

Added new tests.
2023-06-14 16:57:09 +02:00
Charlie Marsh
6f10aeebaa Remove unused Scope#delete method (#5085)
## Summary

This is now intentionally unused and is now made impossible (via this
PR).
2023-06-14 14:15:14 +00:00
Charlie Marsh
c74ef77e85 Move binding accesses into SemanticModel method (#5084) 2023-06-14 14:07:46 +00:00
Charlie Marsh
1e497162d1 Add a dedicated read result for unbound locals (#5083)
## Summary

Small follow-up to #4888 to add a dedicated `ResolvedRead` case for
unbound locals, mostly for clarity and documentation purposes (no
behavior changes).

## Test Plan

`cargo test`
2023-06-14 09:58:48 -04:00
Charlie Marsh
aa41ffcfde Add BindingKind variants to represent deleted bindings (#5071)
## Summary

Our current mechanism for handling deletions (e.g., `del x`) is to
remove the symbol from the scope's `bindings` table. This "does the
right thing", in that if we then reference a deleted symbol, we're able
to determine that it's unbound -- but it causes a variety of problems,
mostly in that it makes certain bindings and references unreachable
after-the-fact.

Consider:

```python
x = 1
print(x)
del x
```

If we analyze this code _after_ running the semantic model over the AST,
we'll have no way of knowing that `x` was ever introduced in the scope,
much less that it was bound to a value, read, and then deleted --
because we effectively erased `x` from the model entirely when we hit
the deletion.

In practice, this will make it impossible for us to support local symbol
renames. It also means that certain rules that we want to move out of
the model-building phase and into the "check dead scopes" phase wouldn't
work today, since we'll have lost important information about the source
code.

This PR introduces two new `BindingKind` variants to model deletions:

- `BindingKind::Deletion`, which represents `x = 1; del x`.
- `BindingKind::UnboundException`, which represents:

```python
try:
  1 / 0
except Exception as e:
  pass
```

In the latter case, `e` gets unbound after the exception handler
(assuming it's triggered), so we want to handle it similarly to a
deletion.

The main challenge here is auditing all of our existing `Binding` and
`Scope` usages to understand whether they need to accommodate deletions
or otherwise behave differently. If you look one commit back on this
branch, you'll see that the code is littered with `NOTE(charlie)`
comments that describe the reasoning behind changing (or not) each of
those call sites. I've also augmented our test suite in preparation for
this change over a few prior PRs.

### Alternatives

As an alternative, I considered introducing a flag to `BindingFlags`,
like `BindingFlags::UNBOUND`, and setting that at the appropriate time.

This turned out to be a much more difficult change, because we tend to
match on `BindingKind` all over the place (e.g., we have a bunch of code
blocks that only run when a `BindingKind` is
`BindingKind::Importation`). As a result, introducing these new
`BindingKind` variants requires only a few changes at the client sites.
Adding a flag would've required a much wider-reaching change.
2023-06-14 09:27:24 -04:00
Dhruv Manilawala
bf5fbf8971 Add GitHub CODEOWNERS file (#5054)
## Summary

Add GitHub CODEOWNERS file.

Initiating this, we can discuss and iterate further.

https://help.github.com/articles/about-codeowners/

## Test Plan

Look out for review requests :)
2023-06-14 05:21:59 +00:00
Charlie Marsh
fc6580592d Use Expr::is_* methods at more call sites (#5075) 2023-06-14 04:02:39 +00:00
Tom Kuson
4d9b0b925d Add documentation to flake8-executable rules (#5063)
## Summary

Completes the documentation for the `flake8-executable` rules.

Related to #2646.

## Test Plan

`python scripts/check_docs_formatted.py`
2023-06-14 01:31:06 +00:00
Charlie Marsh
0daeea1f42 Tweak exception-handler handling in AST visitor (#5069) 2023-06-14 01:00:42 +00:00
Charlie Marsh
3f6584b74f Fix erroneous kwarg reference (#5068) 2023-06-14 00:01:52 +00:00
Charlie Marsh
c2fa568b46 Use dedicated structs for excepthandler variants (#5065)
## Summary

Oversight from #5042.
2023-06-13 22:37:06 +00:00
Charlie Marsh
1895011ac2 Document some attributes on the semantic model (#5064) 2023-06-13 20:45:24 +00:00
Charlie Marsh
364bd82aee Don't treat annotations as resolved in forward references (#5060)
## Summary

This behavior dates back to a Pyflakes commit (5fc37cbd), which was used
to allow this test to pass:

```py
from __future__ import annotations
T: object
def f(t: T): pass
def g(t: 'T'): pass
```

But, I think this is an error. Mypy and Pyright don't accept it -- you
can only use variables as type annotations if they're type aliases
(i.e., annotated with `TypeAlias`), in which case, there has to be an
assignment on the right-hand side (see: [PEP
613](https://peps.python.org/pep-0613/)).
2023-06-13 14:47:29 -04:00
Charlie Marsh
f9f08d6b03 Add a few more tests for deletion behaviors (#5058) 2023-06-13 17:54:04 +00:00
Charlie Marsh
b0984a2868 Treat exception binding as explicit deletion (#5057)
## Summary

This PR corrects a misunderstanding I had related to Python's handling
of bound exceptions.

Previously, I thought this code ran without error:

```py
def f():
    x = 1

    try:
        1 / 0
    except Exception as x:
        pass

    print(x)
```

My understanding was that `except Exception as x` bound `x` within the
`except` block, but then restored the `x = 1` binding after exiting the
block.

In practice, however, this throws a `UnboundLocalError` error, because
`x` becomes "unbound" after exiting the exception handler. It's similar
to a `del` statement in this way.

This PR removes our behavior to "restore" the previous binding. This
could lead to faulty analysis in conditional blocks due to our lack of
control flow analysis, but those same problems already exist for `del`
statements.
2023-06-13 13:45:51 -04:00
Charlie Marsh
a431dd0368 Respect all __all__ definitions for docstring visibility (#5052)
## Summary

We changed the semantics around `__all__` in #4885, but didn't update
the docstring visibility code to match those changes.
2023-06-13 12:22:20 -04:00
Charlie Marsh
099a9152d1 Use .is_unbound() in flake8-errmsg fix (#5053)
## Summary

Trying to bring some more consistent to these APIs as I look to change
them to accommodate deletions.
2023-06-13 12:22:05 -04:00
Charlie Marsh
19f972a305 Use Scope#has in lieu of Scope#get (#5051)
## Summary

These usages don't actually need the `BindingId`.
2023-06-13 15:59:53 +00:00
Thomas de Zeeuw
b0f89fa814 Support glob patterns in pep8_naming ignore-names (#5024)
## Summary

 Support glob patterns in pep8_naming ignore-names.

Closes #2787

## Test Plan

Added new tests.
2023-06-13 17:37:13 +02:00
Charlie Marsh
65312bad01 Remove unannotated attributes from RUF008 (#5049)
## Summary

In a dataclass:

```py
from dataclasses import dataclass

@dataclass
class X:
    class_var = {}
    x: int
```

`class_var` isn't actually a dataclass attribute, since it's
unannotated. This PR removes such attributes from RUF008
(`mutable-dataclass-default`), but it does enforce them in RUF012
(`mutable-class-default`), since those should be annotated with
`ClassVar` like any other mutable class attribute.

Closes #5043.
2023-06-13 10:21:14 -04:00
Aarni Koskela
7b4dde0c6c Add JSON Lines (NDJSON) message serialization (#5048)
## Summary

This adds `json-lines` (https://jsonlines.org/ or http://ndjson.org/) as
an output format.

I'm sure you already know, but

* JSONL is more greppable (each record is a single line) than the pretty
JSON
* JSONL is faster to ingest piecewise (and/or in parallel) than JSON

## Test Plan

Snapshot test in the new module :)
2023-06-13 14:15:55 +00:00
Thomas de Zeeuw
e1fd3965a2 Start with Upper case in error messages (#5045)
## Summary

To be consistent with the format used by other errors.

## Test Plan

N/A.
2023-06-13 13:14:45 +02:00
konstin
95ee6dcb3b Add contributor docs to formatter (#5023)
I've written done my condensed learnings from working on the formatter
so that others can have an easier start working on it.

This is a pure docs change
2023-06-13 07:22:17 +00:00
Charlie Marsh
cc44349401 Use dedicated structs in comparable.rs (#5042)
## Summary

Updating to match the updated AST structure, for consistency.
2023-06-13 03:57:34 +00:00
qdegraaf
a477720f4e [perflint] Add perflint plugin, add first rule PERF102 (#4821)
## Summary

Adds boilerplate for implementing the
[perflint](https://github.com/tonybaloney/perflint/) plugin, plus a
first rule.

## Test Plan

Fixture added for PER8102

## Issue link

Refers: https://github.com/charliermarsh/ruff/issues/4789
2023-06-13 01:54:44 +00:00
Charlie Marsh
be2fa6d217 Increase density of Checker arms (#5041) 2023-06-13 01:08:23 +00:00
Charlie Marsh
cbd4c10fdd Support 'reason' argument to pytest.fail (#5040)
## Summary

Per the [API
reference](https://docs.pytest.org/en/7.1.x/reference/reference.html#pytest.fail),
`reason` was added in version 7, and is equivalent to `msg` (but
preferred going forward).

I also grepped for `msg` usages in `flake8_pytest_style`, but found no
others (apart from those that reference `unittest` APIs.)

Closes #3387.
2023-06-12 20:54:07 -04:00
Timofei Kukushkin
e2130707f5 Autofixer for ISC001 (#4853)
## Summary

This PR adds autofixer for rule ISC001 in cases where both string
literals are of the same kind and with same quotes (double / single).

Fixes #4829

## Test Plan

I added testcases with different combinations of string literals.
2023-06-12 23:28:57 +00:00
Charlie Marsh
780336db0a Include f-string prefixes in quote-stripping utilities (#5039)
Mentioned here:
https://github.com/astral-sh/ruff/pull/4853#discussion_r1217560348.

Generated with this hacky script:
https://gist.github.com/charliermarsh/8ecc4e55bc87d51dc27340402f33b348.
2023-06-12 18:25:47 -04:00
Charlie Marsh
7e37d8916c Remove lexer dependency from identifier_range (#5036)
## Summary

We run this quite a bit -- the new version is zero-allocation, though
it's not quite as nice as the lexer we have in the formatter.
2023-06-12 22:06:03 +00:00
Charlie Marsh
ab11dd08df Improve TypedDict conversion logic for shadowed builtins and dunder methods (#5038)
## Summary

This PR (1) avoids flagging `TypedDict` and `NamedTuple` conversions
when attributes are dunder methods, like `__dict__`, and (2) avoids
flagging the `A003` shadowed-attribute rule for `TypedDict` classes at
all, where it doesn't really apply (since those attributes are only
accessed via subscripting anyway).

Closes #5027.
2023-06-12 21:23:39 +00:00
Charlie Marsh
4080f36850 Handle decorators in class-parenthesis-modifying rules (#5034)
## Summary

A few of our rules look at the parentheses that follow a class
definition (e.g., `class Foo(object):`) and attempt to modify those
parentheses. Neither of those rules were behaving properly in the
presence of decorators, which were recently added to the statement
range.

## Test Plan

`cargo test` with a variety of new fixture tests.
2023-06-12 15:19:59 -04:00
Charlie Marsh
6d861743c8 Remove custom tests in rules/ruff/mod.rs (#5033) 2023-06-12 18:54:04 +00:00
Charlie Marsh
54e103fc99 Add a rule to remove unnecessary parentheses in class definitions (#5032)
Closes #2409.
2023-06-12 18:43:06 +00:00
Dhruv Manilawala
3470dee7d4 Add rule to disallow implicit optional with autofix (#4831)
## Summary

Add rule to disallow implicit optional with autofix.

Currently, I've added it under `RUF` category.

### Limitation

Type aliases could result in false positive:

```python
from typing import Optional

StrOptional = Optional[str]


def foo(arg: StrOptional = None):
	pass
```

## Test Plan

`cargo test`

resolves: #1983

---------

Co-authored-by: Micha Reiser <micha@reiser.io>
Co-authored-by: Charlie Marsh <charlie.r.marsh@gmail.com>
2023-06-12 18:12:10 +00:00
Dhruv Manilawala
cb4f086cbf Add roundtrip support for Jupyter notebook (#5028)
## Summary

Add roundtrip support for Jupyter notebook.

1. Read the notebook
2. Extract out the source code content
3. Use it to update the notebook itself (should be exactly the same [^1])
4. Serialize into JSON and print it to stdout

## Test Plan

`cargo run --all-features --bin ruff_dev --package ruff_dev --
round-trip <path/to/notebook.ipynb>`

<details><summary>Example output:</summary>
<p>

```
{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "f3c286e9-fa52-4440-816f-4449232f199a",
   "metadata": {},
   "source": [
    "# Ruff Test"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a2b7bc6c-778a-4b07-86ae-dde5a2d9511e",
   "metadata": {},
   "source": [
    "Markdown block before the first import"
   ]
  },
  {
   "cell_type": "code",
   "id": "5e3ef98e-224c-450a-80e6-be442ad50907",
   "metadata": {
    "tags": []
   },
   "source": "",
   "execution_count": 1,
   "outputs": []
  },
  {
   "cell_type": "code",
   "id": "6bced3f8-e0a4-450c-ae7c-f60ad5671ee9",
   "metadata": {},
   "source": "import contextlib\n\nwith contextlib.suppress(ValueError):\n    print()\n",
   "outputs": []
  },
  {
   "cell_type": "code",
   "id": "d7102cfd-5bb5-4f5b-a3b8-07a7b8cca34c",
   "metadata": {},
   "source": "import random\n\nrandom.randint(10, 20)",
   "outputs": []
  },
  {
   "cell_type": "code",
   "id": "88471d1c-7429-4967-898f-b0088fcb4c53",
   "metadata": {},
   "source": "foo = 1\nif foo < 2:\n    msg = f\"Invalid foo: {foo}\"\n    raise ValueError(msg)",
   "outputs": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python (ruff-playground)",
   "name": "ruff-playground",
   "language": "python"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "pygments_lexer": "ipython3",
   "nbconvert_exporter": "python",
   "version": "3.11.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
```

</p>
</details> 

[^1]: The type in JSON might be different (https://github.com/astral-sh/ruff/pull/4665#discussion_r1212663495)

Part of #1218
2023-06-12 23:27:45 +05:30
Charlie Marsh
a77d2df934 Split mutable-class-defaults rules into separate modules (#5031) 2023-06-12 17:21:28 +00:00
Adam Pauls
638c18f007 Expand RUF008 to all classes, but to a new code (RUF012) (#4390)
AFAIK, there is no reason to limit RUF008 to just dataclasses -- mutable
defaults have the same problems for regular classes.

Partially addresses https://github.com/charliermarsh/ruff/issues/4053
and broken out from https://github.com/charliermarsh/ruff/pull/4096.

---------

Co-authored-by: Micha Reiser <micha@reiser.io>
Co-authored-by: Charlie Marsh <charlie.r.marsh@gmail.com>
2023-06-12 16:54:27 +00:00
Addison Crump
70e6c212d9 Improve ruff_parse_simple to find UTF-8 violations (#5008)
Improves the `ruff_parse_simple` fuzz harness by adding checks for
parsed locations to ensure they all lie on UTF-8 character boundaries.
This will allow for faster identification of issues like #5004.

This also adds additional details for Apple M1 users and clarifies the
importance of using `init-fuzzer.sh` (thanks for the feedback,
@jasikpark 🙂).
2023-06-12 12:10:23 -04:00
Charlie Marsh
9db622afe1 Allow Options-to-Settings conversion to use TryFrom (#5025)
## Summary

This avoids a bad `expect()` call in the `copyright` conversion.

## Test Plan

`cargo test`
2023-06-12 15:31:50 +00:00
Thomas de Zeeuw
d3aa81a474 Suggest combining async with statements (#5022)
## Summary

Previously the rule for SIM117 explicitly ignored `async with`
statements as it would incorrectly suggestion to merge `async with` and
regular `with` statements as reported in issue #1902.

This partially reverts the fix for that (commit
396be5edea) by enabling the rules for
`async with` statements again, but with a check ensuring that the
statements are both of the same kind, i.e. both `async with` or both
(just) `with` statements.

Closes #3025

## Test Plan

Updated and existing test and added a new test case from #3025.
2023-06-12 16:33:18 +02:00
Dhruv Manilawala
d8f5d2d767 Add support for auto-fix in Jupyter notebooks (#4665)
## Summary

Add support for applying auto-fixes in Jupyter Notebook.

### Solution

Cell offsets are the boundaries for each cell in the concatenated source
code. They are represented using `TextSize`. It includes the start and
end offset as well, thus creating a range for each cell. These offsets
are updated using the `SourceMap` markers.

### SourceMap

`SourceMap` contains markers constructed from each edits which tracks
the original source code position to the transformed positions. The
following drawing might make it clear:

![SourceMap visualization](https://github.com/astral-sh/ruff/assets/67177269/3c94e591-70a7-4b57-bd32-0baa91cc7858)

The center column where the dotted lines are present are the markers
included in the `SourceMap`. The `Notebook` looks at these markers and
updates the cell offsets after each linter loop. If you notice closely,
the destination takes into account all of the markers before it.

The index is constructed only when required as it's only used to render
the diagnostics. So, a `OnceCell` is used for this purpose. The cell
offsets, cell content and the index will be updated after each iteration
of linting in the mentioned order. The order is important here as the
content is updated as per the new offsets and index is updated as per
the new content.

## Limitations

### 1

Styling rules such as the ones in `pycodestyle` will not be applicable
everywhere in Jupyter notebook, especially at the cell boundaries. Let's
take an example where a rule suggests to have 2 blank lines before a
function and the cells contains the following code:

```python
import something
# ---
def first():
	pass

def second():
	pass
```

(Again, the comment is only to visualize cell boundaries.)

In the concatenated source code, the 2 blank lines will be added but it
shouldn't actually be added when we look in terms of Jupyter notebook.
It's as if the function `first` is at the start of a file.

`nbqa` solves this by recording newlines before and after running
`autopep8`, then running the tool and restoring the newlines at the end
(refer https://github.com/nbQA-dev/nbQA/pull/807).

## Test Plan

Three commands were run in order with common flags (`--select=ALL
--no-cache --isolated`) to isolate which stage the problem is occurring:
1. Only diagnostics
2. Fix with diff (`--fix --diff`)
3. Fix (`--fix`)

### https://github.com/facebookresearch/segment-anything

```
-------------------------------------------------------------------------------
 Jupyter Notebooks       3            0            0            0            0
 |- Markdown             3           98            0           94            4
 |- Python               3          513          468            4           41
 (Total)                            611          468           98           45
-------------------------------------------------------------------------------
```

```console
$ cargo run --all-features --bin ruff -- check --no-cache --isolated --select=ALL /path/to/segment-anything/**/*.ipynb --fix
...
Found 180 errors (89 fixed, 91 remaining).
```

### https://github.com/openai/openai-cookbook

```
-------------------------------------------------------------------------------
 Jupyter Notebooks      65            0            0            0            0
 |- Markdown            64         3475           12         2507          956
 |- Python              65         9700         7362         1101         1237
 (Total)                          13175         7374         3608         2193
===============================================================================
```

```console
$ cargo run --all-features --bin ruff -- check --no-cache --isolated --select=ALL /path/to/openai-cookbook/**/*.ipynb --fix
error: Failed to parse /path/to/openai-cookbook/examples/vector_databases/Using_vector_databases_for_embeddings_search.ipynb:cell 4:29:18: unexpected token '-'
...
Found 4227 errors (2165 fixed, 2062 remaining).
```

### https://github.com/tensorflow/docs

```
-------------------------------------------------------------------------------
 Jupyter Notebooks     150            0            0            0            0
 |- Markdown             1           55            0           46            9
 |- Python               1          402          289           60           53
 (Total)                            457          289          106           62
-------------------------------------------------------------------------------
```

```console
$ cargo run --all-features --bin ruff -- check --no-cache --isolated --select=ALL /path/to/tensorflow-docs/**/*.ipynb --fix
error: Failed to parse /path/to/tensorflow-docs/site/en/guide/extension_type.ipynb:cell 80:1:1: unexpected token Indent
error: Failed to parse /path/to/tensorflow-docs/site/en/r1/tutorials/eager/custom_layers.ipynb:cell 20:1:1: unexpected token Indent
error: Failed to parse /path/to/tensorflow-docs/site/en/guide/data.ipynb:cell 175:5:14: unindent does not match any outer indentation level
error: Failed to parse /path/to/tensorflow-docs/site/en/r1/tutorials/representation/unicode.ipynb:cell 30:1:1: unexpected token Indent
...
Found 12726 errors (5140 fixed, 7586 remaining).
```

### https://github.com/tensorflow/models

```
-------------------------------------------------------------------------------
 Jupyter Notebooks      46            0            0            0            0
 |- Markdown             1           11            0            6            5
 |- Python               1          328          249           19           60
 (Total)                            339          249           25           65
-------------------------------------------------------------------------------
```

```console
$ cargo run --all-features --bin ruff -- check --no-cache --isolated --select=ALL /path/to/tensorflow-models/**/*.ipynb --fix
...
Found 4856 errors (2690 fixed, 2166 remaining).
```

resolves: #1218
fixes: #4556
2023-06-12 14:14:15 +00:00
konstin
e586c27590 Format ExprTuple (#4963)
This implements formatting ExprTuple, including magic trailing comma. I
intentionally didn't change the settings mechanism but just added a
dummy global const flag.

Besides the snapshots, I added custom breaking/joining tests and a
deeply nested test case. The diffs look better than previously, proper
black compatibility depends on parentheses handling.

---------

Co-authored-by: Micha Reiser <micha@reiser.io>
2023-06-12 12:55:47 +00:00
Thomas de Zeeuw
8161757229 [flake8-pyi] Implement PYI044 (#5021)
## Summary

This implements PYI044. This rule checks if `from __future__ import
annotations` is used in stub files as it has no effect in stub files, since type
checkers automatically treat stubs as having those semantics.

Updates https://github.com/astral-sh/ruff/issues/848

## Test Plan

Added a test case and snapshots.
2023-06-12 13:20:16 +02:00
Charlie Marsh
6a5f317362 Use use::* for rule re-exports (#5018) 2023-06-12 00:32:45 +00:00
Dhruv Manilawala
c3d1fa851e Ignore pyproject.toml for adding noqa directives (#5013)
## Summary

Ignore pyproject.toml file for adding noqa directives using `--add-noqa`

## Test Plan

`cargo run --bin ruff -- check --add-noqa .`

fixes: #5012
2023-06-11 20:21:24 -04:00
Charlie Marsh
eac3a0cc3d Update CONTRIBUTING.md guide (#5017) 2023-06-12 00:20:59 +00:00
Charlie Marsh
31067e6ce2 Update list of crates in CONTRIBUTING.md (#5016) 2023-06-11 20:10:37 -04:00
Charlie Marsh
68b6d30c46 Use consistent Cargo.toml metadata in all crates (#5015) 2023-06-12 00:02:40 +00:00
Ryan Yang
ab3c02342b Implement copyright notice detection (#4701)
## Summary

Add copyright notice detection to enforce the presence of copyright
headers in Python files.

Configurable settings include: the relevant regular expression, the
author name, and the minimum file size, similar to
[flake8-copyright](https://github.com/savoirfairelinux/flake8-copyright).

Closes https://github.com/charliermarsh/ruff/issues/3579

---------

Signed-off-by: ryan <ryang@waabi.ai>
Co-authored-by: Charlie Marsh <charlie.r.marsh@gmail.com>
2023-06-11 02:17:58 +00:00
Trevor Gross
9f7cc86a22 Add more details to E722 (bare-except) docs (#5007)
## Summary

Note that catching a bare `Exception` is better than catching no
specific exception.

## Test Plan

Documentation only.
2023-06-10 18:42:43 -04:00
Charlie Marsh
445e1723ab Use Stmt::parse in lieu of Suite unwraps (#5002) 2023-06-10 04:55:31 +00:00
Charlie Marsh
42c8054268 Implement autofix for revised RET504 rule (#4999)
## Summary

This PR enables autofix for the revised `RET504` rule, by changing:

```py
def f():
    x = 1
    return x
```

...to:

```py
def f():
    return 1
```

Closes #2263.

Closes #2788.
2023-06-10 04:32:03 +00:00
Charlie Marsh
2d597bc1fb Parenthesize expressions prior to lexing in F632 (#5001) 2023-06-10 04:23:43 +00:00
Charlie Marsh
7275c16d98 Extend revised RET504 implementation to with statements (#4998)
## Summary

This PR extends the new `RET504` implementation to handle cases like:

```py
def foo():
    with open("foo.txt", "r") as f:
        x = f.read()
    return x
```

This was originally suggested in
https://github.com/astral-sh/ruff/issues/2950#issuecomment-1433441503.
2023-06-10 04:15:35 +00:00
Charlie Marsh
02b8ce82af Refactor RET504 to only enforce assignment-then-return pattern (#4997)
## Summary

The `RET504` rule, which looks for unnecessary assignments before return
statements, is a frequent source of issues (#4173, #4236, #4242, #1606,
#2950). Over time, we've tried to refine the logic to handle more cases.
For example, we now avoid analyzing any functions that contain any
function calls or attribute assignments, since those operations can
contain side effects (and so we mark them as a "read" on all variables
in the function -- we could do a better job with code graph analysis to
handle this limitation, but that'd be a more involved change.) We also
avoid flagging any variables that are the target of multiple
assignments. Ultimately, though, I'm not happy with the implementation
-- we just can't do sufficiently reliable analysis of arbitrary code
flow given the limited logic herein, and the existing logic is very hard
to reason about and maintain.

This PR refocuses the rule to only catch cases of the form:

```py
def f():
    x = 1
    return x
```

That is, we now only flag returns that are immediately preceded by an
assignment to the returned variable. While this is more limiting, in
some ways, it lets us flag more cases vis-a-vis the previous
implementation, since we no longer "fully eject" when functions contain
function calls and other effect-ful operations.

Closes #4173.

Closes #4236.

Closes #4242.
2023-06-10 00:05:01 -04:00
Charlie Marsh
5abb8ec0dc Use Python whitespace utilities in ruff_textwrap (#4996)
## Summary

This change was intended to be included in #4994, but was somehow
dropped.
2023-06-10 02:32:42 +00:00
Charlie Marsh
f401050878 Introduce PythonWhitespace to confine trim operations to Python whitespace (#4994)
## Summary

We use `.trim()` and friends in a bunch of places, to strip whitespace
from source code. However, not all Unicode whitespace characters are
considered "whitespace" in Python, which only supports the standard
space, tab, and form-feed characters.

This PR audits our usages of `.trim()`, `.trim_start()`, `.trim_end()`,
and `char::is_whitespace`, and replaces them as appropriate with a new
`.trim_whitespace()` analogues, powered by a `PythonWhitespace` trait.

In general, the only place that should continue to use `.trim()` is
content within docstrings, which don't need to adhere to Python's
semantic definitions of whitespace.

Closes #4991.
2023-06-09 21:44:50 -04:00
Charlie Marsh
c1ac50093c Use super visibility in helpers (#4995) 2023-06-10 01:23:13 +00:00
Charlie Marsh
1d756dc3a7 Move Python whitespace utilities into new ruff_python_whitespace crate (#4993)
## Summary

`ruff_newlines` becomes `ruff_python_whitespace`, and includes the
existing "universal newline" handlers alongside the Python
whitespace-specific utilities.
2023-06-10 00:59:57 +00:00
Charlie Marsh
e86f12a1ec Rename some methods on SemanticModel (#4990) 2023-06-09 19:36:59 +00:00
Charlie Marsh
5c502a3320 Add documentation for BindingKind variants (#4989) 2023-06-09 18:32:50 +00:00
Micha Reiser
901bcb6f21 Fix line numbers in source frames (#4984) 2023-06-09 17:21:18 +02:00
Micha Reiser
111e1f93ca perf(formatter): Skip bodies without comments (#4978) 2023-06-09 11:33:57 +02:00
Micha Reiser
68d52da43b Track formatted comments (#4979) 2023-06-09 09:09:45 +00:00
Micha Reiser
646ab64850 Fix binary expression formatting with leading comments (#4964) 2023-06-09 09:02:50 +00:00
Micha Reiser
1accbeffd6 Format if statements (#4961) 2023-06-09 10:55:14 +02:00
konstin
548a3cbb3f Small CI improvements (#4953)
* Replace the unmaintained actions-rs/cargo that github actions
complains about using an old node version with plain cargo (this was the
original motivation for this PR)
* Use taiki-e/install-action to install critcmp directly
* Use a rust 1.70 nightly toolchain for udeps
* Cache python package build (this should cut a good chunk of ci time)
* yaml formatting courtesy of pycharm

Test Plan: CI itself
2023-06-09 09:03:34 +02:00
Charlie Marsh
16d1e63a5e Respect 'is not' operators split across newlines (#4977) 2023-06-09 05:07:45 +00:00
Charlie Marsh
d647105e97 Support concatenated string key removals (#4976) 2023-06-09 04:56:35 +00:00
Davide Canton
63fdcea29e Handled dict and set inside f-string (#4249) (#4563) 2023-06-09 04:53:13 +00:00
qdegraaf
2bb32ee943 [flake8-slots] Add plugin, add SLOT000, SLOT001 and SLOT002 (#4909) 2023-06-09 04:14:16 +00:00
rodjunger
ee1f094834 [ruff] Add a rule for static keys in dict comprehensions (#4929) 2023-06-09 02:06:34 +00:00
Tom Kuson
efd8f3bdab Complete flake8-simplify documentation (#4930) 2023-06-09 02:02:41 +00:00
Charlie Marsh
293889a352 Support concatenated literals in format-literals (#4974) 2023-06-09 01:29:19 +00:00
Tom Kuson
2c19000e4a Add Pylint rule comparison-with-itself (R0124) (#4957) 2023-06-09 00:57:50 +00:00
Charlie Marsh
aba073a791 Upgrade explicit-type-conversion rule (RUF010) to remove unnecessary str calls (#4971) 2023-06-08 20:02:57 +00:00
Charlie Marsh
d042eddccc Remove unwrap from none-comparison rule (#4969) 2023-06-08 18:21:56 +00:00
Charlie Marsh
775d247731 Allow private accesses within special dunder methods (#4968) 2023-06-08 17:36:49 +00:00
Charlie Marsh
58d08219e8 Allow re-assignments to __all__ (#4967) 2023-06-08 17:19:56 +00:00
Charlie Marsh
902c4e7d77 Make SIM118 a suggested fix (#4966) 2023-06-08 17:02:42 +00:00
Micha Reiser
68969240c5 Format Function definitions (#4951) 2023-06-08 16:07:33 +00:00
Dhruv Manilawala
07cc4bcb0f Update links to point to Astral org (#4949) 2023-06-08 11:43:40 -04:00
Micha Reiser
9c3fb23ace Simple lexer for formatter (#4922) 2023-06-08 17:37:39 +02:00
konstin
467df23e65 Implement StmtReturn (#4960)
* Implement StmtPass

This implements StmtPass as `pass`.

The snapshot diff is small because pass mainly occurs in bodies and function (#4951) and if/for bodies.

* Implement StmtReturn

This implements StmtReturn as `return` or `return {value}`.

The snapshot diff is small because return occurs in functions (#4951)
2023-06-08 16:29:39 +02:00
konstin
c8442e91ce Implement StmtPass (#4959)
This implements StmtPass as `pass`.

The snapshot diff is small because pass mainly occurs in bodies and function (#4951) and if/for bodies.
2023-06-08 16:29:27 +02:00
Micha Reiser
6bef347a8e Trailing own line comments before func or class (#4921) 2023-06-08 12:50:25 +00:00
Micha Reiser
c1cc6f3be1 Add basic Constant formatting (#4954) 2023-06-08 11:42:44 +00:00
Micha Reiser
83cf6d6e2f Implement Binary expression without best_fitting (#4952) 2023-06-08 12:45:03 +02:00
konstin
23abad0bd5 A basic StmtAssign formatter and better dummies for expressions (#4938)
* A basic StmtAssign formatter and better dummies for expressions

The goal of this PR was formatting StmtAssign since many nodes in the black tests (and in python in general) are after an assignment. This caused unstable formatting: The spacing of power op spacing depends on the type of the two involved expressions, but each expression was formatted as dummy string and re-parsed as a ExprName, so in the second round the different rules of ExprName were applied, causing unstable formatting.

This PR does not necessarily bring us closer to black's style, but it unlocks a good porting of black's test suite and is a basis for implementing the Expr nodes.

* fmt

* Review
2023-06-08 12:20:25 +02:00
konstin
651d89794c Use phf for confusables to reduce llvm lines (#4926)
* Use phf for confusables to reduce llvm lines

## Summary

This replaces FxHashMap for the confusables with a perfect hash map from the [phf crate](https://github.com/rust-phf/rust-phf) to reduce the generated llvm instructions.

A perfect hash function is one that doesn't have any collisions. We can build one because we know all keys at compile time. This improves hashmap efficiency, even though this is likely not noticeable in our case (except someone has a large non-english crate to test on).

The original hashmap contained a lot of duplicates, which i had to remove when phf_map complained, i did so by sorting the keys.

The important part that it reduces the llvm instructions generated (#3808, `RUSTFLAGS="-Csymbol-mangling-version=v0" cargo llvm-lines -p ruff --lib | head -20`):

```
  Lines                  Copies               Function name
  -----                  ------               -------------
  1740502                38973                (TOTAL)
    27423 (1.6%,  1.6%)      1 (0.0%,  0.0%)  ruff[cef4c65d96248843]::rules::ruff::rules::confusables::CONFUSABLES::{closure#0}
    10193 (0.6%,  2.2%)      1 (0.0%,  0.0%)  <ruff[cef4c65d96248843]::codes::RuleCodePrefix>::iter
     8107 (0.5%,  2.6%)      1 (0.0%,  0.0%)  <ruff[cef4c65d96248843]::codes::Rule>::noqa_code
     7345 (0.4%,  3.0%)      1 (0.0%,  0.0%)  <ruff[cef4c65d96248843]::checkers::ast::Checker as ruff_python_ast[3778b140caf21545]::visitor::Visitor>::visit_stmt
     6412 (0.4%,  3.4%)      1 (0.0%,  0.0%)  <<ruff[cef4c65d96248843]::settings::options::Options as serde[d89b1b632568f5a3]::de::Deserialize>::deserialize::__Visitor as serde[d89b1b632568f5a3]::de::Visitor>::visit_map::<toml_edit[7e3a6c5e67260672]::de::spanned::SpannedDeserializer<toml_edit[7e3a6c5e67260672]::de::value::ValueDeserializer>>
     6412 (0.4%,  3.8%)      1 (0.0%,  0.0%)  <<ruff[cef4c65d96248843]::settings::options::Options as serde[d89b1b632568f5a3]::de::Deserialize>::deserialize::__Visitor as serde[d89b1b632568f5a3]::de::Visitor>::visit_map::<toml_edit[7e3a6c5e67260672]::de::table::TableMapAccess>
     6409 (0.4%,  4.2%)      1 (0.0%,  0.0%)  <<ruff[cef4c65d96248843]::settings::options::Options as serde[d89b1b632568f5a3]::de::Deserialize>::deserialize::__Visitor as serde[d89b1b632568f5a3]::de::Visitor>::visit_map::<toml_edit[7e3a6c5e67260672]::de::datetime::DatetimeDeserializer>
     5696 (0.3%,  4.5%)      1 (0.0%,  0.0%)  <ruff[cef4c65d96248843]::checkers::ast::Checker as ruff_python_ast[3778b140caf21545]::visitor::Visitor>::visit_expr
     4448 (0.3%,  4.7%)      1 (0.0%,  0.0%)  ruff[cef4c65d96248843]::flake8_to_ruff::converter::convert
     3702 (0.2%,  4.9%)      1 (0.0%,  0.0%)  <&ruff[cef4c65d96248843]::registry::Linter as core[da82827a87f140f9]::iter::traits::collect::IntoIterator>::into_iter
     3349 (0.2%,  5.1%)      1 (0.0%,  0.0%)  <ruff[cef4c65d96248843]::registry::Linter>::code_for_rule
     3132 (0.2%,  5.3%)      1 (0.0%,  0.0%)  <ruff[cef4c65d96248843]::codes::Rule as core[da82827a87f140f9]::fmt::Debug>::fmt
     3130 (0.2%,  5.5%)      1 (0.0%,  0.0%)  <&str as core[da82827a87f140f9]::convert::From<&ruff[cef4c65d96248843]::codes::Rule>>::from
     3130 (0.2%,  5.7%)      1 (0.0%,  0.0%)  <&str as core[da82827a87f140f9]::convert::From<ruff[cef4c65d96248843]::codes::Rule>>::from
     3130 (0.2%,  5.9%)      1 (0.0%,  0.0%)  <ruff[cef4c65d96248843]::codes::Rule as core[da82827a87f140f9]::convert::AsRef<str>>::as_ref
     3128 (0.2%,  6.0%)      1 (0.0%,  0.0%)  <ruff[cef4c65d96248843]::codes::RuleIter>::get
     2669 (0.2%,  6.2%)      1 (0.0%,  0.0%)  <<ruff[cef4c65d96248843]::settings::options::Options as serde[d89b1b632568f5a3]::de::Deserialize>::deserialize::__Visitor as serde[d89b1b632568f5a3]::de::Visitor>::visit_seq::<toml_edit[7e3a6c5e67260672]::de::array::ArraySeqAccess>
```
After:
```
  Lines                  Copies               Function name
  -----                  ------               -------------
  1710487                38900                (TOTAL)
    10193 (0.6%,  0.6%)      1 (0.0%,  0.0%)  <ruff[52408f46d2058296]::codes::RuleCodePrefix>::iter
     8107 (0.5%,  1.1%)      1 (0.0%,  0.0%)  <ruff[52408f46d2058296]::codes::Rule>::noqa_code
     7345 (0.4%,  1.5%)      1 (0.0%,  0.0%)  <ruff[52408f46d2058296]::checkers::ast::Checker as ruff_python_ast[5588cd60041c8605]::visitor::Visitor>::visit_stmt
     6412 (0.4%,  1.9%)      1 (0.0%,  0.0%)  <<ruff[52408f46d2058296]::settings::options::Options as serde[d89b1b632568f5a3]::de::Deserialize>::deserialize::__Visitor as serde[d89b1b632568f5a3]::de::Visitor>::visit_map::<toml_edit[7e3a6c5e67260672]::de::spanned::SpannedDeserializer<toml_edit[7e3a6c5e67260672]::de::value::ValueDeserializer>>
     6412 (0.4%,  2.2%)      1 (0.0%,  0.0%)  <<ruff[52408f46d2058296]::settings::options::Options as serde[d89b1b632568f5a3]::de::Deserialize>::deserialize::__Visitor as serde[d89b1b632568f5a3]::de::Visitor>::visit_map::<toml_edit[7e3a6c5e67260672]::de::table::TableMapAccess>
     6409 (0.4%,  2.6%)      1 (0.0%,  0.0%)  <<ruff[52408f46d2058296]::settings::options::Options as serde[d89b1b632568f5a3]::de::Deserialize>::deserialize::__Visitor as serde[d89b1b632568f5a3]::de::Visitor>::visit_map::<toml_edit[7e3a6c5e67260672]::de::datetime::DatetimeDeserializer>
     5696 (0.3%,  3.0%)      1 (0.0%,  0.0%)  <ruff[52408f46d2058296]::checkers::ast::Checker as ruff_python_ast[5588cd60041c8605]::visitor::Visitor>::visit_expr
     4448 (0.3%,  3.2%)      1 (0.0%,  0.0%)  ruff[52408f46d2058296]::flake8_to_ruff::converter::convert
     3702 (0.2%,  3.4%)      1 (0.0%,  0.0%)  <&ruff[52408f46d2058296]::registry::Linter as core[da82827a87f140f9]::iter::traits::collect::IntoIterator>::into_iter
     3349 (0.2%,  3.6%)      1 (0.0%,  0.0%)  <ruff[52408f46d2058296]::registry::Linter>::code_for_rule
     3132 (0.2%,  3.8%)      1 (0.0%,  0.0%)  <ruff[52408f46d2058296]::codes::Rule as core[da82827a87f140f9]::fmt::Debug>::fmt
     3130 (0.2%,  4.0%)      1 (0.0%,  0.0%)  <&str as core[da82827a87f140f9]::convert::From<&ruff[52408f46d2058296]::codes::Rule>>::from
     3130 (0.2%,  4.2%)      1 (0.0%,  0.0%)  <&str as core[da82827a87f140f9]::convert::From<ruff[52408f46d2058296]::codes::Rule>>::from
     3130 (0.2%,  4.4%)      1 (0.0%,  0.0%)  <ruff[52408f46d2058296]::codes::Rule as core[da82827a87f140f9]::convert::AsRef<str>>::as_ref
     3128 (0.2%,  4.5%)      1 (0.0%,  0.0%)  <ruff[52408f46d2058296]::codes::RuleIter>::get
     2669 (0.2%,  4.7%)      1 (0.0%,  0.0%)  <<ruff[52408f46d2058296]::settings::options::Options as serde[d89b1b632568f5a3]::de::Deserialize>::deserialize::__Visitor as serde[d89b1b632568f5a3]::de::Visitor>::visit_seq::<toml_edit[7e3a6c5e67260672]::de::array::ArraySeqAccess>
     2659 (0.2%,  4.9%)      1 (0.0%,  0.0%)  <&ruff[52408f46d2058296]::codes::Pylint as core[da82827a87f140f9]::iter::traits::collect::IntoIterator>::into_iter
```

I'd assume this has a positive effect both on compile time and on runtime, but i don't know the actual effect on compile times and can't really measure.

## Test plan

Check CI for any performance regressions.

This should fix #3808 if we merge it.

* clippy

* Update update_ambiguous_characters.py
2023-06-08 08:13:20 +02:00
Micha Reiser
39a1f3980f Upgrade RustPython (#4900) 2023-06-08 05:53:14 +00:00
Charlie Marsh
4b78141f6b Generate one fix per statement for flake8-type-checking rules (#4915) 2023-06-07 22:22:35 -04:00
Charlie Marsh
5235977abc Bump version to 0.0.272 (#4948) 2023-06-08 02:17:29 +00:00
kyoto7250
01d3d4bbd2 ignore if using infinite iterators in B905 (#4914) 2023-06-08 02:12:50 +00:00
Charlie Marsh
ac4a4da50e Handle implicit string concatenations in conversion-flag rewrites (#4947) 2023-06-08 02:04:35 +00:00
Charlie Marsh
a6d269f263 Apply dict.get fix before ternary rewrite (#4944) 2023-06-07 22:33:40 +00:00
Charlie Marsh
f17282d615 Skip class scopes when resolving nonlocal references (#4943) 2023-06-07 22:25:36 +00:00
Dhruv Manilawala
6950c93934 Make C413 fix as suggested for reversed call (#4891) 2023-06-07 18:23:19 -04:00
Charlie Marsh
ae75b303f0 Avoid attributing runtime references to module-level imports (#4942) 2023-06-07 21:56:03 +00:00
Charlie Marsh
20240fc3d9 Move flake8-fixme rules to FIX prefix (#4917) 2023-06-07 21:14:49 +00:00
Addison Crump
f990d9dcc5 Remove libafl_libfuzzer while it remains unstable (#4933) 2023-06-07 19:56:37 +02:00
konstin
5c48414093 Use taiki-e/install-action to install cargo fuzz (#4928)
* Use taiki-e/install-action to install cargo fuzz

The cargo fuzz run seems to sometimes fail for unclear reasons (https://github.com/charliermarsh/ruff/actions/runs/5200348677/jobs/9379742606?pr=4900). I hope that this might fix it. I'll push more commits to this PR to check the caching behaviour.

* Trigger CI with cache

* Change cache

* Actually use caching

* Undo cargo update

* cargo update fuzzer

* Revert rust changes
2023-06-07 15:57:33 +00:00
Micha Reiser
bcf745c5ba Replace verbatim text with NOT_YET_IMPLEMENTED (#4904)
<!--
Thank you for contributing to Ruff! To help us out with reviewing, please consider the following:

- Does this pull request include a summary of the change? (See below.)
- Does this pull request include a descriptive title?
- Does this pull request include references to any relevant issues?
-->

## Summary

This PR replaces the `verbatim_text` builder with a `not_yet_implemented` builder that emits `NOT_YET_IMPLEMENTED_<NodeKind>` for not yet implemented nodes. 

The motivation for this change is that partially formatting compound statements can result in incorrectly indented code, which is a syntax error:

```python
def func_no_args():
  a; b; c
  if True: raise RuntimeError
  if False: ...
  for i in range(10):
    print(i)
    continue
```

Get's reformatted to

```python
def func_no_args():
    a; b; c
    if True: raise RuntimeError
    if False: ...
    for i in range(10):
    print(i)
    continue
```

because our formatter does not yet support `for` statements and just inserts the text from the source. 

## Downsides

Using an identifier will not work in all situations. For example, an identifier is invalid in an `Arguments ` position. That's why I kept `verbatim_text` around and e.g. use it in the `Arguments` formatting logic where incorrect indentations are impossible (to my knowledge). Meaning, `verbatim_text` we can opt in to `verbatim_text` when we want to iterate quickly on nodes that we don't want to provide a full implementation yet and using an identifier would be invalid. 

## Upsides

Running this on main discovered stability issues with the newline handling that were previously "hidden" because of the verbatim formatting. I guess that's an upside :)

## Test Plan

None?
2023-06-07 14:57:25 +02:00
Addison Crump
2f125f4019 Create fuzzers for testing correctness of parsing, linting and fixing (#4822)
Co-authored-by: Micha Reiser <micha@reiser.io>
2023-06-07 14:57:07 +02:00
Micha Reiser
6ab3fc60f4 Correctly handle newlines after/before comments (#4895)
<!--
Thank you for contributing to Ruff! To help us out with reviewing, please consider the following:

- Does this pull request include a summary of the change? (See below.)
- Does this pull request include a descriptive title?
- Does this pull request include references to any relevant issues?
-->

## Summary

This issue fixes the removal of empty lines between a leading comment and the previous statement:

```python
a  = 20

# leading comment
b = 10
```

Ruff removed the empty line between `a` and `b` because:
* The leading comments formatting does not preserve leading newlines (to avoid adding new lines at the top of a body)
* The `JoinNodesBuilder` counted the lines before `b`, which is 1 -> Doesn't insert a new line

This is fixed by changing the `JoinNodesBuilder` to count the lines instead *after* the last node. This correctly gives 1, and the `# leading comment` will insert the empty lines between any other leading comment or the node.



## Test Plan

I added a new test for empty lines.
2023-06-07 14:49:43 +02:00
Charlie Marsh
222ca98a41 Add contents: write permission to release step (#4911) 2023-06-07 08:42:27 -04:00
Charlie Marsh
ec609f5c3b Clarify requires-python inference requirements (#4918) 2023-06-07 04:18:56 +00:00
Justin Prieto
b9060ea2bd [flake8-pyi] Implement PYI050 (#4884) 2023-06-07 01:56:53 +00:00
Charlie Marsh
b56a799417 Add some more test coverage for del statements (#4913) 2023-06-06 21:40:23 -04:00
Charlie Marsh
780d153ae8 Replace one-off locals property with ScopeFlags (#4912) 2023-06-06 21:22:21 -04:00
Tom Kuson
7cc205b5d6 Change iteration-over-set to flag set literals only (#4907) 2023-06-06 21:06:46 +00:00
Charlie Marsh
e1df2b1400 Set default Rust version when testing sdist (#4908) 2023-06-06 16:59:04 -04:00
Charlie Marsh
2a6d7cd71c Avoid no-op fix for nested with expressions (#4906) 2023-06-06 20:15:21 +00:00
Charlie Marsh
2b5fb70482 Bump version to 0.0.271 (#4890) 2023-06-06 15:11:48 -04:00
Charlie Marsh
8c048b463c Track symbol deletions separately from bindings (#4888) 2023-06-06 18:49:36 +00:00
Micha Reiser
19abee086b Introduce AnyFunctionDefinition Node (#4898) 2023-06-06 20:37:46 +02:00
Addison Crump
1ed5d7e437 mark f522 as sometimes fixable (#4893) 2023-06-06 09:14:23 -04:00
Micha Reiser
3f032cf09d Format binary expressions (#4862)
* Format Binary Expressions

* Extract NeedsParentheses trait
2023-06-06 08:34:53 +00:00
konstin
775326790e Fix pre-commit typos action (#4876)
The typos pre-commit action would also edit test fixtures and snapshots. Unfortunately the pre-commit action also doesn't respect _typos.toml and typos action doesn't allow for an exclude key, so i've added a top level exclude key. I have confirmed that this does stop typos from rewriting my fixtures and snapshots
2023-06-06 08:06:48 +02:00
Charlie Marsh
7b0fb1a3b4 Respect noqa directives on ImportFrom parents for type-checking rules (#4889) 2023-06-06 02:37:07 +00:00
Charlie Marsh
c2a3e97b7f Avoid early-exit in explicit-f-string-type-conversion (#4886) 2023-06-06 00:52:11 +00:00
Charlie Marsh
805b2eb0b7 Respect shadowed exports in __all__ (#4885) 2023-06-05 20:48:53 -04:00
Charlie Marsh
0c7ea800af Remove destructive fixes for F523 (#4883) 2023-06-06 00:44:30 +00:00
Charlie Marsh
c67029ded9 Move duplicate-value rule to flake8-bugbear (#4882) 2023-06-05 21:43:47 +00:00
Charlie Marsh
a70afa7de7 Remove ToString prefixes (#4881) 2023-06-05 21:11:19 +00:00
Charlie Marsh
d1b8fe6af2 Fix round-tripping of nested functions (#4875) 2023-06-05 16:13:08 -04:00
Micha Reiser
913b9d1fcf Normalize newlines in verbatim_text (#4850) 2023-06-05 19:30:28 +00:00
Justin Prieto
f9e82f2578 [flake8-pyi] Implement PYI029 (#4851) 2023-06-05 19:21:16 +00:00
Charlie Marsh
79ae1840af Remove unused lifetime from UnusedImport type alias (#4874) 2023-06-05 19:09:27 +00:00
Charlie Marsh
8938b2d555 Use qualified_name terminology in more structs for consistency (#4873) 2023-06-05 19:06:48 +00:00
Micha Reiser
33434fcb9c Add Formatter benchmark (#4860) 2023-06-05 21:05:42 +02:00
Charlie Marsh
8a3a269eef Avoid index-out-of-bands panic for positional placeholders (#4872) 2023-06-05 18:31:47 +00:00
Charlie Marsh
d31eb87877 Extract shared simple AST node inference utility (#4871) 2023-06-05 18:23:37 +00:00
Ryan Yang
72245960a1 implement E307 for pylint invalid str return type (#4854) 2023-06-05 17:54:15 +00:00
Charlie Marsh
e6b00f0c4e Avoid running RUF100 rules when code contains syntax errors (#4869) 2023-06-05 17:32:06 +00:00
Charlie Marsh
f952bef1ad Mark F523 as "sometimes" fixable (#4868) 2023-06-05 16:55:28 +00:00
Allison Karlitskaya
dc223fd3ca Add some exceptions for FBT003 (#3247) (#4867) 2023-06-05 16:44:49 +00:00
konstin
209aaa5add Ensure type_ignores for Module are empty (#4861)
According to https://docs.python.org/3/library/ast.html#ast-helpers, we expect type_ignores to be always be empty, so this adds a debug assert.

Test plan: I confirmed that the assertion holdes for the file below and for all the black tests which include a number of `type: ignore` comments.
```python
# type: ignore

if 1:
    print("1")  # type: ignore
    # elsebranch

# type: ignore

else:  # type: ignore
    print("2")  # type: ignore

while 1:
    print()

# type: ignore
```
2023-06-05 11:38:08 +02:00
konstin
ff37d7af23 Implement module formatting using JoinNodesBuilder (#4808)
* Implement module formatting using JoinNodesBuilder

This uses JoinNodesBuilder to implement module formatting for #4800

See the snapshots for the changed behaviour. See one PR up for a CLI that i used to verify the trailing new line behaviour
2023-06-05 08:35:05 +00:00
Micha Reiser
c65f47d7c4 Format while Statement (#4810) 2023-06-05 08:24:00 +00:00
konstin
d1d06960f0 Add a formatter CLI for debugging (#4809)
* Add a formatter CLI for debugging

This adds a ruff_python_formatter cli modelled aber `rustfmt` that i use for debugging

* clippy

* Add print IR and print comments options

Tested with `cargo run --bin ruff_python_formatter -- --print-ir --print-comments scratch.py`
2023-06-05 07:33:33 +00:00
konstin
576e0c7b80 Abstract stylist to libcst style conversion (#4749)
* Abstract codegen with stylist into a CodegenStylist trait

Replace all duplicate invocations of

```rust
let mut state = CodegenState {
    default_newline: &stylist.line_ending(),
    default_indent: stylist.indentation(),
    ..CodegenState::default()
}
tree.codegen(&mut state);
state.to_string()
```

with

```rust
tree.codegen_stylist(&stylist);
```

No functional changes.
2023-06-05 07:22:43 +00:00
Charlie Marsh
1fba98681e Remove codes import from rule_selector.rs (#4856) 2023-06-05 02:31:30 +00:00
Evan Rittenhouse
95e61987d1 Change fixable_set to include RuleSelector::All/Nursery (#4852) 2023-06-04 22:25:00 -04:00
Charlie Marsh
a0721912a4 Invert structure of Scope#shadowed_bindings (#4855) 2023-06-05 02:03:21 +00:00
Micha Reiser
694bf7f5b8 Upgrade to Rust 1.70 (#4848) 2023-06-04 17:51:47 +00:00
Charlie Marsh
466719247b Invert parent-shadowed bindings map (#4847) 2023-06-04 00:18:46 -04:00
Charlie Marsh
3fa4440d87 Modify semantic model API to push bindings upon creation (#4846) 2023-06-04 02:28:25 +00:00
Zanie Adkins
14e06f9f8b Rename ruff_formatter::builders::BestFitting to FormatBestFitting (#4841) 2023-06-04 00:13:51 +02:00
Zanie Adkins
e7a2e0f437 Remove unused mutable variables (#4839) 2023-06-03 17:31:06 -04:00
Evan Rittenhouse
67b43ab72a Make FLY002 autofix into a constant string instead of an f-string if all join() arguments are strings (#4834) 2023-06-03 20:35:06 +00:00
Zanie Adkins
5ae4667fd5 Upgrade criterion to 0.5.1 (#4838) 2023-06-03 21:33:44 +01:00
Charlie Marsh
d8a6109b69 Fix min-index offset rewrites in F523 (#4837) 2023-06-03 20:11:48 +00:00
Charlie Marsh
fcacd3cd95 Preserve quotes in F523 fixer (#4836) 2023-06-03 19:53:57 +00:00
Charlie Marsh
42c071d302 Respect mixed variable assignment in RET504 (#4835) 2023-06-03 15:39:11 -04:00
Charlie Marsh
c14896b42c Move Binding initialization into SemanticModel (#4819) 2023-06-03 15:26:55 -04:00
Charlie Marsh
935094c2ff Move import-name matching into methods on BindingKind (#4818) 2023-06-03 15:01:27 -04:00
Micha Reiser
2c41c54e0c Format ExprName (#4803) 2023-06-03 16:06:14 +02:00
Micha Reiser
d6daa61563 Handle trailing end-of-line comments in-between-bodies (#4812)
<!--
Thank you for contributing to Ruff! To help us out with reviewing, please consider the following:

- Does this pull request include a summary of the change? (See below.)
- Does this pull request include a descriptive title?
- Does this pull request include references to any relevant issues?
-->

## Summary

And more custom logic around comments in bodies... uff. 

Let's say we have the following code

```python
if x == y:
    pass # trailing comment of pass
else: # trailing comment of `else`
    print("I have no comments")
```

Right now, the formatter attaches the `# trailing comment of `else` as a trailing comment of `pass` because it doesn't "see" that there's an `else` keyword in between (because the else body is just a Vec and not a node). 

This PR adds custom logic that attaches the trailing comments after the `else` as dangling comments to the `if` statement. The if statement must then split the dangling comments by `comments.text_position()`:
* All comments up to the first end-of-line comment are leading comments of the `else` keyword.
* All end-of-line comments coming after are `trailing` comments for the `else` keyword.


## Test Plan

I added new unit tests.
2023-06-03 15:29:22 +02:00
Micha Reiser
cb6788ab5f Handle trailing body end-of-line comments (#4811)
### Summary

This PR adds custom logic to handle end-of-line comments of the last statement in a body. 

For example: 

```python
while True:
    if something.changed:
        do.stuff()  # trailing comment

b
```

The `# trailing comment` is a trailing comment of the `do.stuff()` expression statement. We incorrectly attached the comment as a trailing comment of the enclosing `while` statement  because the comment is between the end of the while statement (the `while` statement ends right after `do.stuff()`) and before the `b` statement. 


This PR fixes the placement to correctly attach these comments to the last statement in a body (recursively). 

## Test Plan

I reviewed the snapshots and they now look correct. This may appear odd because a lot comments have now disappeared. This is the expected result because we use `verbatim` formatting for the block statements (like `while`) and that means that it only formats the inner content of the block, but not any trailing comments. The comments were visible before, because they were associated with the block statement (e.g. `while`).
2023-06-03 15:17:33 +02:00
Justin Prieto
e82160a83a [flake8-pyi] Implement PYI035 (#4820) 2023-06-03 03:13:04 +00:00
Charlie Marsh
26b1dd0ca2 Remove name field from import binding kinds (#4817) 2023-06-02 23:02:47 -04:00
Charlie Marsh
fcfd6ad129 Rename outlier Pathlib rule (#4816) 2023-06-02 18:42:17 +00:00
Charlie Marsh
6a0cebdf7b Remove regex from partial-path rule (#4815) 2023-06-02 18:28:55 +00:00
Ville Skyttä
0a5dfcb26a Implement S609, linux_commands_wildcard_injection (#4504) 2023-06-02 18:19:02 +00:00
Charlie Marsh
3ff1f003f4 Omit internal and documentation changes from changelog (#4814) 2023-06-02 15:39:37 +00:00
Micha Reiser
ebdc4afc33 Suite formatting and JoinNodesBuilder (#4805) 2023-06-02 14:14:38 +00:00
Jonathan Plasse
03ee6033f9 Fix flake8-fixme architecture (#4807) 2023-06-02 09:15:44 -04:00
Micha Reiser
a401989b7a Format StmtExpr (#4788) 2023-06-02 12:52:38 +00:00
Micha Reiser
4cd4b37e74 Format the comment content (#4786) 2023-06-02 11:22:34 +00:00
konstin
602b4b3519 Merge registry into codes (#4651)
* Document codes.rs

* Refactor codes.rs before merging

Helper script:
```python
# %%

from pathlib import Path

codes = Path("crates/ruff/src/codes.rs").read_text().splitlines()
rules = Path("a.txt").read_text().strip().splitlines()
rule_map = {i.split("::")[-1]: i for i in rules}

# %%

codes_new = []
for line in codes:
    if ", Rule::" in line:
        left, right = line.split(", Rule::")
        right = right[:-2]
        line = left + ", " + rule_map[right] + "),"
    codes_new.append(line)

# %%

Path("crates/ruff/src/codes.rs").write_text("\n".join(codes_new))
```

Co-authored-by: Jonathan Plasse <13716151+JonathanPlasse@users.noreply.github.com>
2023-06-02 10:33:01 +00:00
konstin
c4fdbf8903 Switch PyFormatter lifetimes (#4804)
Stylistic change to have the input lifetime first and the output lifetime second. I'll rebase my other PR on top of this.

Test plan: `cargo clippy`
2023-06-02 12:26:39 +02:00
Micha Reiser
5d939222db Leading, Dangling, and Trailing comments formatting (#4785) 2023-06-02 09:26:36 +02:00
Evan Rittenhouse
b2498c576f Implement flake8_fixme and refactor TodoDirective (#4681) 2023-06-02 08:18:47 +02:00
Micha Reiser
c89d2f835e Add to AnyNode and AnyNodeRef conversion methods to AstNode (#4783) 2023-06-02 08:10:41 +02:00
Charlie Marsh
211d8e170d Ignore error calls with exc_info in TRY400 (#4797) 2023-06-02 04:59:45 +00:00
Charlie Marsh
b92be59ffe Remove some matches on Stmt (#4796) 2023-06-02 04:36:36 +00:00
Charlie Marsh
b030c70dda Move unused imports rule into its own module (#4795) 2023-06-02 04:27:23 +00:00
Charlie Marsh
10ba79489a Exclude function definition from too-many-statements rule (#4794) 2023-06-02 04:04:25 +00:00
Charlie Marsh
ea3cbcc362 Avoid enforcing native-literals rule within nested f-strings (#4488) 2023-06-02 04:00:31 +00:00
Charlie Marsh
b8f45c93b4 Use a separate fix-isolation group for every parent node (#4774) 2023-06-02 03:07:55 +00:00
Charlie Marsh
621718784a Replace deletion-tracking with enforced isolation levels (#4766) 2023-06-02 02:45:56 +00:00
qdegraaf
fcbf5c3fae Add PYI034 for flake8-pyi plugin (#4764) 2023-06-02 02:15:57 +00:00
Justin Prieto
c68686b1de [flake8-pyi] Implement PYI054 (#4775) 2023-06-02 01:21:27 +00:00
Justin Prieto
583411a29f [flake8-pyi] Implement PYI053 (#4770) 2023-06-01 23:00:15 +00:00
qdegraaf
6d94aa89e3 [flake8-pyi] Implement PYI025 (#4791) 2023-06-01 22:45:31 +00:00
Sladyn
8d5d34c6d1 Migrate flake8_pyi_rules from unspecified to suggested and automatic (#4750) 2023-06-01 22:35:47 +00:00
Jonathan Plasse
edadd7814f Add pyflakes.extend-generics setting (#4677) 2023-06-01 22:19:37 +00:00
Charlie Marsh
3180f9978a Avoid extra newline between diagnostics in grouped mode (#4776) 2023-06-01 21:33:29 +00:00
Tom Kuson
bdff4a66ac Add Pylint rule C0208 (use-sequence-for-iteration) as PLC0208 (iteration-over-set) (#4706) 2023-06-01 21:26:23 +00:00
Charlie Marsh
ab26f2dc9d Use saturating_sub in more token-walking methods (#4773) 2023-06-01 17:16:32 -04:00
Dhruv Manilawala
0099f9720f Add autofix for PLR1701 (repeated-isinstance-calls) (#4792) 2023-06-01 20:43:04 +00:00
Tom Kuson
d9fdcebfc1 Complete the Pyflakes documention (#4787) 2023-06-01 20:25:32 +00:00
Charlie Marsh
b7038cee13 Include ImportError in non-fixable try-catch imports (#4793) 2023-06-01 19:53:49 +00:00
Charlie Marsh
be740106e0 Remove some lexer usages from Insertion (#4763) 2023-06-01 19:45:43 +00:00
konstin
63d892f1e4 Implement basic module formatting (#4784)
* Add Format for Stmt

* Implement basic module formatting

This implements formatting each statement in a module with a hard line break in between, so that we can start formatting statements.

Basic testing is done by the snapshots
2023-06-01 15:25:50 +02:00
Micha Reiser
28aad95414 Remove collapsing space behaviour from Printer (#4782) 2023-06-01 13:38:42 +02:00
Micha Reiser
5f4bce6d2b Implement IntoFormat for &T (#4781) 2023-06-01 12:20:49 +02:00
Micha Reiser
4ea4fd1984 Introduce lines_before helper (#4780) 2023-06-01 11:56:43 +02:00
konstin
d4027d8b65 Use new formatter infrastructure in CLI and test (#4767)
* Use dummy verbatim formatter for all nodes

* Use new formatter infrastructure in CLI and test

* Expose the new formatter in the CLI

* Merge import blocks
2023-06-01 11:55:04 +02:00
konstin
9bf168c0a4 Use dummy verbatim formatter for all nodes (#4755) 2023-06-01 08:25:26 +00:00
Micha Reiser
59148344be Place comments of left and right binary expression operands (#4751) 2023-06-01 07:01:32 +00:00
konstin
0945803427 Generate FormatRule definitions (#4724)
* Generate FormatRule definitions

* Generate verbatim output

* pub(crate) everything

* clippy fix

* Update crates/ruff_python_formatter/src/lib.rs

Co-authored-by: Micha Reiser <micha@reiser.io>

* Update crates/ruff_python_formatter/src/lib.rs

Co-authored-by: Micha Reiser <micha@reiser.io>

* stub out with Ok(()) again

* Update crates/ruff_python_formatter/src/lib.rs

Co-authored-by: Micha Reiser <micha@reiser.io>

* PyFormatContext::{contents, locator} with `#[allow(unused)]`

* Can't leak private type

* remove commented code

* Fix ruff errors

* pub struct Format{node} due to rust rules

---------

Co-authored-by: Julian LaNeve <lanevejulian@gmail.com>
Co-authored-by: Micha Reiser <micha@reiser.io>
2023-06-01 08:38:53 +02:00
Micha Reiser
b7294b48e7 Handle positional-only-arguments separator comments (#4748) 2023-06-01 06:22:49 +00:00
Micha Reiser
be31d71849 Correctly associate own-line comments in bodies (#4671) 2023-06-01 08:12:53 +02:00
Charlie Marsh
46c3b3af94 Use ALL in fixable documentation (#4772) 2023-05-31 22:30:12 -04:00
Charlie Marsh
3d34d9298d Remove erroneous method calls in flake8-unused-arguments docs (#4771) 2023-06-01 02:23:59 +00:00
Charlie Marsh
1156c65be1 Add autofix to move runtime-imports out of type-checking blocks (#4743) 2023-05-31 18:09:04 +00:00
Charlie Marsh
1a53996f53 Add autofix for flake8-type-checking (#4742) 2023-05-31 17:53:36 +00:00
Charlie Marsh
4bd395a850 Apply edits in sorted order (#4762) 2023-05-31 17:26:31 +00:00
Charlie Marsh
bb4f3dedf4 Enable start-of-block insertions (#4741) 2023-05-31 17:08:43 +00:00
Jonathan Plasse
01470d9045 Add E201, E202, E203 auto-fix (#4723) 2023-05-31 16:53:47 +00:00
Charlie Marsh
0b471197dc Extract lower-level edit utility from autofix module (#4737) 2023-05-31 16:50:54 +00:00
Charlie Marsh
399eb84d5e Add a ruff_textwrap crate (#4731) 2023-05-31 16:35:23 +00:00
konstin
35cd57d0fc Make running ruff on ruff possible (#4760)
I was wondering why `pip install -U ruff && ruff .` in the ruff repo would result in only noise while the pre-commit ruff works. Turns out the pre-commit has an exclude for the resources directories.

This adds the excludes from pre-commit to ruff's own pyproject.toml so `ruff .` works on ruff itself
2023-05-31 18:19:15 +02:00
qdegraaf
2b2812c4f2 Add PYI024 for flake8-pyi plugin (#4756) 2023-05-31 16:07:04 +00:00
Charlie Marsh
9d0ffd33ca Move universal newline handling into its own crate (#4729) 2023-05-31 12:00:47 -04:00
Micha Reiser
e209b5fc5f Add reformat check (#4753) 2023-05-31 17:36:15 +02:00
Alex Fikl
c1286d61df Ignore __setattr__ in FBT003 (#4752) 2023-05-31 10:36:19 -04:00
Micha Reiser
6c1ff6a85f Upgrade RustPython (#4747) 2023-05-31 08:26:35 +00:00
Micha Reiser
06bcb85f81 formatter: Remove CST and old formatting (#4730) 2023-05-31 08:27:23 +02:00
Charlie Marsh
d7a4999915 Flag empty strings in flake8-errmsg rules (#4745) 2023-05-31 04:37:43 +00:00
Charlie Marsh
d4e54cff05 Make organize imports an automatic edit (#4744) 2023-05-31 04:29:04 +00:00
Charlie Marsh
e1b6f6e57e Refactor flake8-type-checking rules to take Checker (#4739) 2023-05-30 22:51:44 +00:00
Charlie Marsh
50053f60f3 Rename top-of-file to start-of-file (#4735) 2023-05-30 21:53:36 +00:00
Charlie Marsh
a4f73ea8c7 Remove unused getrandom dependency (#4734) 2023-05-30 14:34:20 -04:00
Charlie Marsh
04a95cb9ee Add Rust toolchain as documentation dependency in CONTRIBUTING.md (#4733) 2023-05-30 17:39:45 +00:00
Charlie Marsh
f9b3f10456 Clarify that [tool.ruff] must be omitted for ruff.toml (#4732) 2023-05-30 17:35:28 +00:00
Charlie Marsh
f47a517e79 Enable callers to specify import-style preferences in Importer (#4717) 2023-05-30 16:46:19 +00:00
Charlie Marsh
ea31229be0 Track TYPE_CHECKING blocks in Importer (#4593) 2023-05-30 16:18:10 +00:00
Charlie Marsh
0854543328 Use a custom error type for symbol-import results (#4688) 2023-05-30 09:19:31 -04:00
Vadim Suharnikov
0bc3d99298 Add devcontainer support (#4676) (#4678) 2023-05-30 14:49:51 +02:00
Micha Reiser
0cd453bdf0 Generic "comment to node" association logic (#4642) 2023-05-30 09:28:01 +00:00
Micha Reiser
84a5584888 Add Comments data structure (#4641) 2023-05-30 08:54:55 +00:00
Micha Reiser
6146b75dd0 Add MultiMap implementation for storing comments (#4639) 2023-05-30 09:51:25 +02:00
Micha Reiser
236074fdde testing_macros: Add missing full feature to syn dependency (#4722) 2023-05-30 07:42:06 +00:00
Charlie Marsh
e323bb015b Move fixable checks into patch blocks (#4721) 2023-05-30 02:09:30 +00:00
Charlie Marsh
80fa3f2bfa Add a convenience method to check if a name is bound (#4718) 2023-05-30 01:52:41 +00:00
Charlie Marsh
1846d90bbd Rename the flake8-future-annotations rules (#4716) 2023-05-29 23:00:08 +00:00
Aarni Koskela
0106bce02f [flake8-future-annotations] Implement FA102 (#4702) 2023-05-29 22:41:45 +00:00
Charlie Marsh
2695d0561a Add ability to generate snapshot tests on code snippets (#4714) 2023-05-29 18:36:12 -04:00
Charlie Marsh
5f715417e0 Remove redundant test descriptions from #test_case macros (#4713) 2023-05-29 18:23:56 -04:00
Jonathan Plasse
f7c2d25205 Remove enumerated plugins in rules page (#4715) 2023-05-29 22:20:41 +00:00
Charlie Marsh
6e096f216a Fix docs formatting for iter-method-returns-iterable (#4712) 2023-05-29 21:34:42 +00:00
Justin Prieto
d0ad4be20e [flake8-pyi] Implement PYI045 (#4700) 2023-05-29 21:27:13 +00:00
Julian LaNeve
6425fe8c12 Update option anchors to include group name (#4711) 2023-05-29 17:26:10 -04:00
Julian LaNeve
68db74b3c5 Add AIR001: task variable name should be same as task_id arg (#4687) 2023-05-29 03:25:06 +00:00
Charlie Marsh
9646bc7d7f Add docs to clarify project root heuristics (#4697) 2023-05-29 02:50:35 +00:00
Julian LaNeve
5756829344 markdownlint: enforce 100 char max length (#4698) 2023-05-28 22:45:56 -04:00
Julian LaNeve
cb45b25879 Add contributing docs specific to rule-testing patterns (#4690) 2023-05-28 22:52:49 +00:00
qdegraaf
0911ce4cbc [flake8-pyi] Add PYI032 rule with autofix (#4695) 2023-05-28 22:41:15 +00:00
Tom Kuson
51f04ee6ef Add more Pyflakes docs (#4689) 2023-05-28 22:29:03 +00:00
Charlie Marsh
dbeadd99a8 Remove impossible states from version-comparison representation (#4696) 2023-05-28 22:08:40 +00:00
Dhruv Manilawala
79b35fc3cc Handle dotted alias imports to check for implicit imports (#4685) 2023-05-27 23:58:03 -04:00
Jonathan Plasse
9f16ae354e Fix UP036 auto-fix error (#4679) 2023-05-28 03:37:22 +00:00
Charlie Marsh
9741f788c7 Remove globals table from Scope (#4686) 2023-05-27 22:35:20 -04:00
Jonathan Plasse
901060fa96 Fix PLW3301 false positive single argument nested min/max (#4683) 2023-05-27 15:34:55 -04:00
Charlie Marsh
f069eb9e3d Fix async for formatting (#4675) 2023-05-27 02:53:33 +00:00
Tom Kuson
fe72bde23c Add Pylint string formatting rule docs (#4638) 2023-05-27 02:47:14 +00:00
Chris Chan
1268ddca92 Implement Pylint's yield-inside-async-function rule (PLE1700) (#4668) 2023-05-27 01:14:41 +00:00
Charlie Marsh
af433ac14d Avoid using typing-imported symbols for runtime edits (#4649) 2023-05-26 20:36:37 -04:00
qdegraaf
ccca11839a Allow more immutable funcs for RUF009 (#4660) 2023-05-26 15:18:52 -04:00
konstin
12e45498e8 Improve token handling (#4653)
* Use release environment

* Use pypi trusted publishing

* typo
2023-05-26 09:52:24 +02:00
Micha Reiser
33a7ed058f Create PreorderVisitor trait (#4658) 2023-05-26 06:14:08 +00:00
qdegraaf
52deeb36ee Implement PYI048 for flake8-pyi plugin (#4645) 2023-05-25 20:04:14 +00:00
Charlie Marsh
0f610f2cf7 Remove dedicated ScopeKind structs in favor of AST nodes (#4648) 2023-05-25 19:31:02 +00:00
Evan Rittenhouse
741e180e2d Change TODO directive detection to work with multiple pound signs on the same line (#4558) 2023-05-25 16:51:45 +02:00
konstin
b6a382eeaf Lint pyproject.toml (#4496)
This adds a new rule `InvalidPyprojectToml` that lints pyproject.toml by checking if https://github.com/PyO3/pyproject-toml-rs can parse it. This means the linting is currently very basic, e.g. we don't check whether the name is actually a valid python project name or appropriately normalized. It does catch errors e.g. with invalid dependency requirements or problems withs the license specifications. It is open to be extended in the future (validate name, SPDX expressions, classifiers, ...), either in ruff or in pyproject-toml-rs.

Test plan:

```
scripts/ecosystem_all_check.sh check --select RUF200
```
This lead to a bunch of 
```
RUF200 Failed to parse pyproject.toml: missing field `name`
```
(e.g. https://github.com/amitsk/fastapi-todos/blob/main/pyproject.toml) which is indeed invalid (https://packaging.python.org/en/latest/specifications/declaring-project-metadata/#specification).

Filtering those out, the following other problems were found by `cd target/ecosystem_all_results/ && rg RUF200`:
```
UCL-ARC:rred-reports.stdout.txt
1:pyproject.toml:27:16: RUF200 Failed to parse pyproject.toml: Version specifier `>='3.9'` doesn't match PEP 440 rules
EndlessTrax:python-start-project.stdout.txt
1:pyproject.toml:14:16: RUF200 Failed to parse pyproject.toml: Expected package name starting with an alphanumeric character, found '#'
redjax:gardening-api.stdout.txt
1:pyproject.toml:7:11: RUF200 Failed to parse pyproject.toml: Version `` doesn't match PEP 440 rules
ajslater:codex.stdout.txt
2:  3:17 RUF200 Failed to parse pyproject.toml: invalid type: sequence, expected a string
LDmitriy7:404_AvatarsBot.stdout.txt
1:pyproject.toml:3:11: RUF200 Failed to parse pyproject.toml: Version `` doesn't match PEP 440 rules
ajslater:comicbox.stdout.txt
1:pyproject.toml:3:17: RUF200 Failed to parse pyproject.toml: invalid type: sequence, expected a string
manueldevillena:forecast-earnings.stdout.txt
1:pyproject.toml:24:12: RUF200 Failed to parse pyproject.toml: Expected one of `@`, `(`, `<`, `=`, `>`, `~`, `!`, `;`, found `^`
redjax:ohio_utility_scraper.stdout.txt
1:pyproject.toml:11:11: RUF200 Failed to parse pyproject.toml: Version `` doesn't match PEP 440 rules
agronholm:typeguard.stdout.txt
1:pyproject.toml:40:8: RUF200 Failed to parse pyproject.toml: Expected a valid marker name, found 'python_implementation'
cyuss:decathlon-turnover.stdout.txt
1:pyproject.toml:7:12: RUF200 Failed to parse pyproject.toml: invalid type: string "Youcef", expected a table with 'name' and 'email' keys
ajslater:boilerplate.stdout.txt
1:pyproject.toml:3:17: RUF200 Failed to parse pyproject.toml: invalid type: sequence, expected a string
kaparoo:lightning-project-template.stdout.txt
1:pyproject.toml:56:16: RUF200 Failed to parse pyproject.toml: You can't mix a >= operator with a local version (`+cu117`)
dijital20:pytexas2023-decorators.stdout.txt
1:pyproject.toml:5:11: RUF200 Failed to parse pyproject.toml: Version `` doesn't match PEP 440 rules
pfouque:django-anymail-history.stdout.txt
1:pyproject.toml:137:12: RUF200 Failed to parse pyproject.toml: Version specifier `> = 1.2.0` doesn't match PEP 440 rules
pfouque:django-fakemessages.stdout.txt
1:pyproject.toml:130:12: RUF200 Failed to parse pyproject.toml: Version specifier `> = 1.2.0` doesn't match PEP 440 rules
pypa:build.stdout.txt
1:tests/packages/test-invalid-requirements/pyproject.toml:2:12: RUF200 Failed to parse pyproject.toml: Expected one of `@`, `(`, `<`, `=`, `>`, `~`, `!`, `;`, found `i`
4:tests/packages/test-no-requires/pyproject.toml:1:1: RUF200 Failed to parse pyproject.toml: missing field `requires`
UnoYakshi:FRAAND.stdout.txt
2:  3:11 RUF200 Failed to parse pyproject.toml: Version `` doesn't match PEP 440 rules
DHolmanCoding:python-template.stdout.txt
1:pyproject.toml:22:1: RUF200 Failed to parse pyproject.toml: missing field `requires`
```
Overall, this emitted errors in 43 out of 3408 projects (`rg -c RUF200 target/ecosystem_all_results/ | wc -l`)


Co-authored-by: Micha Reiser <micha@reiser.io>
2023-05-25 12:05:28 +00:00
qdegraaf
050350527c Add autofix for PYI010 (#4634) 2023-05-24 22:17:44 +00:00
Charlie Marsh
c9b39e31fc Use class name as range for B024 (#4647) 2023-05-24 22:16:13 +00:00
bersbersbers
28a5e607b4 Docs: mention task-tags option in two rules (#4644) 2023-05-24 16:31:41 -04:00
Micha Reiser
09c50c311c Testing Macros: Add extra-traits feature (#4643) 2023-05-24 17:14:58 +00:00
Charlie Marsh
252506f8ed Remove deprecated --universal2 flag (#4640) 2023-05-24 17:00:52 +00:00
Charlie Marsh
f4572fe40b Bump version to 0.0.270 (#4637) 2023-05-24 16:34:29 +00:00
Sladyn
8c9215489e Migrate flake8_bugbear rules to unspecified to suggested (#4616) 2023-05-24 16:16:33 +00:00
qdegraaf
dcd2bfaab7 Migrate flake8_pie autofix rules from unspecified to suggested and automatic (#4621) 2023-05-24 16:08:22 +00:00
Charlie Marsh
f0e173d9fd Use BindingId copies in lieu of &BindingId in semantic model methods (#4633) 2023-05-24 15:55:45 +00:00
Charlie Marsh
f4f1b1d0ee Only run the playground release job on release (#4636) 2023-05-24 11:48:36 -04:00
Micha Reiser
edc6c4058f Move shared_traits to ruff_formatter (#4632) 2023-05-24 17:38:11 +02:00
Jonathan Plasse
4233f6ec91 Update to the new rule architecture (#4589) 2023-05-24 11:30:40 -04:00
Charlie Marsh
fcdc7bdd33 Remove separate ReferenceContext enum (#4631) 2023-05-24 15:12:38 +00:00
Micha Reiser
86ced3516b Introduce SourceCodeSlice to reduce the size of FormatElement (#4622)
Introduce `SourceCodeSlice` to reduce the size of `FormatElement`
2023-05-24 15:04:52 +00:00
Micha Reiser
6943beee66 Remove source position from FormatElement::DynamicText (#4619) 2023-05-24 16:36:14 +02:00
Micha Reiser
85f094f592 Improve Message sorting performance (#4624) 2023-05-24 16:34:48 +02:00
konstin
17d938f078 Add Checker::any_enabled shortcut (#4630)
Add Checker::any_enabled shortcut

 ## Summary

 Akin to #4625, This is a refactoring that shortens a bunch of code by replacing `checker.settings.rules.any_enabled` with `checker.any_enabled`.

 ## Test Plan

 `cargo clippy`
2023-05-24 14:32:55 +00:00
Charlie Marsh
5cedf0f724 Remove ReferenceContext::Synthetic (#4612) 2023-05-24 14:30:35 +00:00
konstin
38297c08b4 Make ecosystem all check more generic (#4629)
* Don't assume unique repo names in ecosystem checks

This fixes a bug where previously repositories with the same name would have been overwritten.

I tested with `scripts/check_ecosystem.py -v --checkouts target/checkouts_main .venv/bin/ruff target/release/ruff` and ruff 0.0.267 that changes are shown. I confirmed with `scripts/ecosystem_all_check.sh check --select RUF008` (next PR) that the checkouts are now complete.

* Make ecosystem all check more generic

This allows passing arguments to the ecosystem all check script, e.g. you can now do `scripts/ecosystem_all_check.sh check --select RUF008`.

Tested with
```
$ cat target/ecosystem_all_results/*.stdout.txt | head
src/fi_parliament_tools/parsing/data_structures.py:33:17: RUF008 Do not use mutable default values for dataclass attributes
src/fi_parliament_tools/parsing/data_structures.py:76:17: RUF008 Do not use mutable default values for dataclass attributes
src/fi_parliament_tools/parsing/data_structures.py:178:17: RUF008 Do not use mutable default values for dataclass attributes
Found 3 errors.
braid_triggers/tasks.py:46:17: RUF008 Do not use mutable default values for dataclass attributes
Found 1 error.
src/boards/RaspberryPi3.py:15:22: RUF008 Do not use mutable default values for dataclass attributes
src/boards/board.py:21:26: RUF008 Do not use mutable default values for dataclass attributes
src/boards/board.py:22:32: RUF008 Do not use mutable default values for dataclass attributes
src/boards/board.py:23:37: RUF008 Do not use mutable default values for dataclass attributes
$ cat target/ecosystem_all_results/*.stdout.txt | wc -l
115
```
2023-05-24 16:26:23 +02:00
konstin
30e90838d0 Don't assume unique repo names in ecosystem checks (#4628)
This fixes a bug where previously repositories with the same name would have been overwritten.

I tested with `scripts/check_ecosystem.py -v --checkouts target/checkouts_main .venv/bin/ruff target/release/ruff` and ruff 0.0.267 that changes are shown. I confirmed with `scripts/ecosystem_all_check.sh check --select RUF008` (next PR) that the checkouts are now complete.
2023-05-24 16:26:12 +02:00
Charlie Marsh
040fb9cef4 Use a separate PrinterFlag for including fix diffs (#4615) 2023-05-24 10:22:37 -04:00
Charlie Marsh
8961d8eb6f Track all read references in semantic model (#4610) 2023-05-24 14:14:27 +00:00
Charlie Marsh
31bddef98f Visit TypeVar and NewType name arguments (#4627) 2023-05-24 10:10:15 -04:00
konstin
a59d252246 Add Checker::enabled shortcut (#4625)
This is a refactoring that shortens a bunch of code by replacing `checker.settings.rules.enabled` with `checker.enabled`
2023-05-24 14:56:41 +02:00
konstin
5b9d4f18ae Remove outdated feature flag from Dockerfile.ecosystem (#4620) 2023-05-24 08:19:08 +00:00
Jonathan Plasse
c6a760e298 Introduce tab-size to correcly calculate the line length with tabulations (#4167) 2023-05-24 08:37:24 +02:00
konstin
3644695bf2 Include hidden ecosystem_ci option to show fixes without feature (#4528) 2023-05-23 22:22:23 -04:00
Evan Rittenhouse
b1d01b1950 Add a PR template (#4582) 2023-05-24 02:17:38 +00:00
Sladyn
4e84e8a8e2 Migrate some rules from Fix::unspecified (#4587) 2023-05-23 22:10:58 -04:00
Hoël Bagard
a256fdb9f4 Extend RUF005 to recursive and literal-literal concatenations (#4557) 2023-05-24 01:26:34 +00:00
Tom Kuson
7479dfd815 Add Pyflakes docs (#4588) 2023-05-24 00:45:32 +00:00
Charlie Marsh
ba4c0a21fa Rename ContextFlags to SemanticModelFlags (#4611) 2023-05-23 17:47:07 -04:00
konstin
73e179ffab Update maturin to 1.0 (#4605)
* Refactor and fix task trigger for dependent jobs in other repos

I have confirmed (https://github.com/konstin/ruff-pre-commit/actions/runs/5056928280/jobs/9075029868) that this does dispatch the workflow when running with act, `owner: 'konstin'`, `needs` commented out and personal access token. I can't properly test the actual release workflow, and i'm unsure how to best handle the next release after this was merged (should we do a beta release or will this break everything that assumes we only do stable releases?)

The command for act is
```
act -j update-dependents -s RUFF_PRE_COMMIT_PAT=<...>
```

* delete old file

* Update maturin to 1.0

A 1.0 release for maturin 🎉
2023-05-23 20:55:52 +02:00
konstin
3cbaaa4795 Refactor and fix task trigger for dependent jobs in other repos (#4598)
* Refactor and fix task trigger for dependent jobs in other repos

I have confirmed (https://github.com/konstin/ruff-pre-commit/actions/runs/5056928280/jobs/9075029868) that this does dispatch the workflow when running with act, `owner: 'konstin'`, `needs` commented out and personal access token. I can't properly test the actual release workflow, and i'm unsure how to best handle the next release after this was merged (should we do a beta release or will this break everything that assumes we only do stable releases?)

The command for act is
```
act -j update-dependents -s RUFF_PRE_COMMIT_PAT=<...>
```

* delete old file
2023-05-23 20:55:35 +02:00
Micha Reiser
2681c0e633 Add missing nodes to AnyNodeRef and AnyNode (#4608) 2023-05-23 18:30:27 +02:00
Charlie Marsh
f3bdd2e7be Make B007 fix relevance stricter (#4607) 2023-05-23 15:43:59 +00:00
Micha Reiser
652c644c2a Introduce ruff_index crate (#4597) 2023-05-23 17:40:35 +02:00
konstin
04d273bcc7 Add a script to update the schemastore (#4574)
* Add a script to update the schemastore

Hacked this together, it clones astral-sh/schemastore, updated the schema and pushes the changes
to a new branch tagged with the ruff git hash. You can see the URL to create the PR
to schemastore in the CLI. The script is separated into three blocks so you can rerun
the schema generation in the middle before committing.

* Use tempdir for schemastore

* Add comments
2023-05-23 10:41:56 +00:00
Micha Reiser
154439728a Add AnyNode and AnyNodeRef unions (#4578) 2023-05-23 08:53:22 +02:00
Jonathan Plasse
1ddc577204 Rework CST matchers (#4536)
Co-authored-by: Micha Reiser <micha@reiser.io>
2023-05-23 06:26:51 +00:00
Charlie Marsh
74effb40b9 Rename index to binding_id in a few iterators (#4594) 2023-05-23 03:56:00 +00:00
Charlie Marsh
6c3724ab98 Move get_or_import_symbol onto Importer (#4591) 2023-05-23 01:33:00 +00:00
Christopher Covington
3b8121379d Name ambiguous characters (#4448) 2023-05-22 17:16:57 +00:00
qdegraaf
5ba47c3302 Add autofix for PYI009 (#4583) 2023-05-22 16:41:18 +00:00
Charlie Marsh
b613460fe5 Fix # isort: split comment detection in nested blocks (#4584) 2023-05-22 12:31:59 -04:00
Micha Reiser
daadd24bde Include decorators in Function and Class definition ranges (#4467) 2023-05-22 17:50:42 +02:00
Charlie Marsh
9308e939f4 Avoid infinite loop for required imports with isort: off (#4581) 2023-05-22 15:49:03 +00:00
Charlie Marsh
04c9348de0 Make ambiguous-unicode detection sensitive to 'word' context (#4552) 2023-05-22 14:42:25 +00:00
Tom Kuson
2d3766d928 Add flake8-boolean-trap docs (#4572) 2023-05-22 14:11:14 +00:00
konstin
550b643e33 Add script for ecosystem wide checks of all rules and fixes (#4326)
* Add script for ecosystem wide checks of all rules and fixes

This adds my personal script for checking an entire checkout of ~2.1k packages for
panics, autofix errors and similar problems. It's not really meant to be used by anybody else but i thought it's better if it lives in the repo than if it doesn't.

For reference, this is the current output of failing autofixes: https://gist.github.com/konstin/c3fada0135af6cacec74f166adf87a00. Trimmed down to the useful information: https://gist.github.com/konstin/c864f4c300c7903a24fdda49635c5da9

* Keep github template intact

* Remove the need for ripgrep

* sort output
2023-05-22 15:23:25 +02:00
Micha Reiser
cbe344f4d5 Rename Checker::model to semantic_model (#4573) 2023-05-22 15:14:30 +02:00
Micha Reiser
063431cb0f Upgrade RustPython (#4576) 2023-05-22 14:50:49 +02:00
Evan Rittenhouse
c6e5fed658 Replace token iteration with Indexer/Locator lookups for relevant rules (#4513) 2023-05-22 09:56:19 +02:00
Charlie Marsh
f73b398776 Reduce visibility of more functions, structs, and fields (#4570) 2023-05-22 03:36:48 +00:00
Charlie Marsh
55c4020ba9 Remove regex for noqa code splitting (#4569) 2023-05-21 23:20:49 -04:00
Charlie Marsh
d70f899f71 Use SemanticModel in lieu of Checker in more methods (#4568) 2023-05-22 02:58:47 +00:00
Charlie Marsh
19c4b7bee6 Rename ruff_python_semantic's Context struct to SemanticModel (#4565) 2023-05-22 02:35:03 +00:00
Jonathan Plasse
3238743a7b Fix Flake8Todo typo (#4566) 2023-05-21 16:32:13 -04:00
Charlie Marsh
f22c269ccf Point LSP, VS Code, and pre-commut URLs to Astral org (#4562) 2023-05-21 15:27:35 -04:00
Arne de Laat
8ca3977602 Fix false-positive for TRY302 if exception cause is given (#4559) 2023-05-21 11:49:53 -04:00
Jacob Coffee
6db05d8cc6 Starlite -> Litestar (#4554) 2023-05-21 09:55:26 -04:00
Jonathan Plasse
fc63c6f2e2 Fix PLE01310 typo (#4550) 2023-05-20 19:34:03 +00:00
Jonathan Plasse
f7f5bc9085 Fix SIM401 snapshot (#4547) 2023-05-20 14:18:19 -04:00
Charlie Marsh
6b85430a14 Ignore #region code folding marks in eradicate rules (#4546) 2023-05-20 16:45:49 +00:00
Jonathan Plasse
a68c865010 Fix SIM110 and SIM111 ranges (#4545) 2023-05-20 12:40:35 -04:00
Charlie Marsh
fe7f2e2e4d Move submodule alias resolution into Context (#4543) 2023-05-20 16:34:10 +00:00
Felipe Peter
0a3cf8ba11 Fix typos in docs (#4540) 2023-05-20 07:23:17 -04:00
Charlie Marsh
bf5b463c0d Include empty success test in JUnit output (#4537) 2023-05-20 03:38:51 +00:00
Charlie Marsh
6aa9900c03 Improve handling of __qualname__, __module__, and __class__ (#4512) 2023-05-20 03:03:45 +00:00
Charlie Marsh
9e21414294 Improve reference resolution for deferred-annotations-within-classes (#4509) 2023-05-20 02:54:18 +00:00
Charlie Marsh
bb4e674415 Move reference-resolution into Context (#4510) 2023-05-20 02:47:15 +00:00
Charlie Marsh
b42ff08612 Parenthesize more sub-expressions in f-string conversion (#4535) 2023-05-19 19:41:30 +00:00
Jonathan Plasse
03fb62c174 Fix RUF010 auto-fix with parenthesis (#4524) 2023-05-19 19:05:51 +00:00
Jonathan Plasse
2dfc645ea9 Fix UP032 auto-fix with integers (#4525) 2023-05-19 18:53:50 +00:00
Hoël Bagard
fe8e2bb237 [pylint] Add named_expr_without_context (W0131) (#4531) 2023-05-19 18:00:01 +00:00
Tom Kuson
a9ed8d5391 Add Pylint docs (#4530) 2023-05-19 17:40:18 +00:00
Aaron Cunningham
41a681531d Support new extend-per-file-ignores setting (#4265) 2023-05-19 12:24:04 -04:00
Justin Prieto
837e70677b [flake8-pyi] Implement PYI013 (#4517) 2023-05-19 15:39:55 +00:00
Hoël Bagard
7ebe372122 [pylint] Add duplicate-value (W0130) (#4515) 2023-05-19 15:03:47 +00:00
konstin
625849b846 Ecosystem CI: Optionally diff fixes (#4193)
* Generate fixes when using --show-fixes

Example command: `cargo run --bin ruff -- --no-cache --select F401
--show-source --show-fixes
crates/ruff/resources/test/fixtures/pyflakes/F401_9.py`

Before, `--show-fixes` was ignored:

```
crates/ruff/resources/test/fixtures/pyflakes/F401_9.py:4:22: F401 [*] `foo.baz` imported but unused
  |
4 | __all__ = ("bar",)
5 | from foo import bar, baz
  |                      ^^^ F401
  |
  = help: Remove unused import: `foo.baz`

Found 1 error.
[*] 1 potentially fixable with the --fix option.
```

After:

```
crates/ruff/resources/test/fixtures/pyflakes/F401_9.py:4:22: F401 [*] `foo.baz` imported but unused
  |
4 | __all__ = ("bar",)
5 | from foo import bar, baz
  |                      ^^^ F401
  |
  = help: Remove unused import: `foo.baz`

ℹ Suggested fix
1 1 | """Test: late-binding of `__all__`."""
2 2 |
3 3 | __all__ = ("bar",)
4   |-from foo import bar, baz
  4 |+from foo import bar

Found 1 error.
[*] 1 potentially fixable with the --fix option.
```

Also fixes git clone
2023-05-19 09:49:57 +00:00
konstin
32f1edc555 Create dummy format CLI (#4453)
* Create dummy format CLI

* Hide format from clap, too

Missed that this is a separate option from `#[doc(hidden)]`

* Remove cargo feature and replace with warning

* No-alloc files parameter matching

* beta warning: warn -> warn_user_once

* Rephrase warning
2023-05-19 11:45:52 +02:00
Micha Reiser
2f35099f81 Remove regex dependency from ruff_python_ast (#4518) 2023-05-19 06:44:18 +00:00
Hoël Bagard
ce8fd31a8f Updated contributing documentation (#4516) 2023-05-19 08:39:15 +02:00
Ville Skyttä
fdb241cad2 [flake8-bandit] Implement paramiko-call (S601) (#4500) 2023-05-19 03:40:50 +00:00
Charlie Marsh
ab303f4e09 Gate schemars skip under feature flag (#4514) 2023-05-19 03:01:31 +00:00
Charlie Marsh
15cb21a6f4 Implement --extend-fixable option (#4297) 2023-05-18 22:20:19 -04:00
Ville Skyttä
2e2ba2cb16 Avoid some false positives in dunder variable assigments (#4508) 2023-05-19 02:11:20 +00:00
Charlie Marsh
d4c0a41b00 Bump version to 0.0.269 (#4506) 2023-05-18 19:45:20 +00:00
Charlie Marsh
8702b5a40a Bump version to 0.0.268 (#4501) 2023-05-18 15:35:46 -04:00
figsoda
bab818e801 Update RustPython dependencies (#4503) 2023-05-18 15:28:13 -04:00
konstin
a3aa841fc9 Overhaul sdist handling (#4439)
* Reduce sdist size

`maturin sdist && du -sh target/wheels/ruff-0.0.267.tar.gz`:
Before: 1,1M
After: 668K

* Test sdist before release

* Update maturin to fix the sdist
2023-05-18 19:02:22 +02:00
Ville Skyttä
fdd894145b S608 improvements (#4499) 2023-05-18 11:27:22 -04:00
Charlie Marsh
85f67b2ee3 Make the AST Checker pub(crate) (#4498) 2023-05-18 15:17:26 +00:00
Charlie Marsh
e9c6f16c56 Move unparse utility methods onto Generator (#4497) 2023-05-18 15:00:46 +00:00
Charlie Marsh
d3b18345c5 Move triple-quoted string detection into Indexer method (#4495) 2023-05-18 14:42:05 +00:00
Jonathan Plasse
0e4d174551 Fix COM812 false positive in string subscript (#4493) 2023-05-18 14:35:41 +00:00
Charlie Marsh
73efbeb581 Invert quote-style when generating code within f-strings (#4487) 2023-05-18 14:33:33 +00:00
Charlie Marsh
2fb312bb2b Fix scoping of comprehensions within classes (#4494) 2023-05-18 14:30:02 +00:00
Charlie Marsh
e8e66f3824 Remove unnecessary path prefixes (#4492) 2023-05-18 10:19:09 -04:00
Charlie Marsh
a8d080c825 Extend multi-line noqa directives to start-of-line (#4490) 2023-05-18 13:05:27 +00:00
Charlie Marsh
ddd541b198 Move Insertion into its own module (#4478) 2023-05-17 21:11:41 +00:00
Tom Kuson
3090aec97d Add PLW docs (#4469) 2023-05-17 18:30:45 +00:00
Charlie Marsh
14c6419bc1 Bring pycodestyle rules into full compatibility (on SciPy) (#4472) 2023-05-17 16:51:55 +00:00
Charlie Marsh
3bc29d6c0c Allow shebang comments at start-of-file (#4473) 2023-05-17 16:32:12 +00:00
Charlie Marsh
67c5086aba Include precise tokens for extraneous-whitespace diagnostics (#4471) 2023-05-17 16:25:17 +00:00
Charlie Marsh
cd82b83f89 Avoid triggering pd#at and friends on non-subscripts (#4474) 2023-05-17 16:20:58 +00:00
Charlie Marsh
39fb2cc732 Remove special-casing for whitespace-around-@ (#4458) 2023-05-17 15:32:08 +00:00
John Kelly
9c732c7946 Implement TRY302 - raise after except (#4461) 2023-05-17 01:36:10 +00:00
Charlie Marsh
2332ea5753 Remove type-complexity ignores from map_codes.rs (#4463) 2023-05-17 01:02:24 +00:00
Charlie Marsh
6b1062ccc3 Enable pycodestyle rules under new "nursery" category (#4407) 2023-05-16 21:21:58 +00:00
Charlie Marsh
39fa38cb35 Enable pycodestyle rules (#3689) 2023-05-16 20:39:43 +00:00
Micha Reiser
ddf7de7e86 Prototype Black's string joining/splitting (#4449) 2023-05-16 18:42:40 +01:00
Charlie Marsh
e5101e8eac Split logical lines tests into one test per assertion (#4457) 2023-05-16 17:40:39 +00:00
Charlie Marsh
d9c3f8e249 Avoid flagging missing whitespace for decorators (#4454) 2023-05-16 13:15:01 -04:00
Charlie Marsh
7e0d018b35 Avoid emitting empty logical lines (#4452) 2023-05-16 16:33:33 +00:00
Jeong, YunWon
4b05ca1198 Specialize ConversionFlag (#4450) 2023-05-16 18:00:13 +02:00
Charlie Marsh
f0465bf106 Emit non-logical newlines for "empty" lines (#4444) 2023-05-16 14:58:56 +00:00
Charlie Marsh
8134ec25f0 Fix expected-indentation errors with end-of-line comments (#4438) 2023-05-16 10:45:54 -04:00
Jeong, YunWon
6049aabe27 Update RustPyhon and enable full-lexer feature (#4442) 2023-05-16 07:19:57 +00:00
Jeong, YunWon
badade3ccc Impl Default for SourceLocation (#4328)
Co-authored-by: Micha Reiser <micha@reiser.io>
2023-05-16 07:03:43 +00:00
Micha Reiser
fa26860296 Refactor range from Attributed to Nodes (#4422) 2023-05-16 06:36:32 +00:00
James Lamb
140e0acf54 Add LightGBM to user list (#4446) 2023-05-16 04:04:37 +00:00
Sladyn
c711db11ce [flake8-pyi] Implement unannotated-assignment-in-stub (PY052) (#4293) 2023-05-16 02:06:55 +00:00
Charlie Marsh
1fe6954150 Fix bidirectional-unicode formatting (#4445) 2023-05-15 22:36:25 +00:00
Charlie Marsh
2414469ac3 Enable automatic rewrites of typing.Deque and typing.DefaultDict (#4420) 2023-05-15 22:33:24 +00:00
Tom Kuson
838ba1ca3d Add PLE rule docs (#4437) 2023-05-15 19:48:18 +00:00
Charlie Marsh
8f3f8d3e0b Revert change to re-run release on tag update (#4441) 2023-05-15 15:48:45 +00:00
qdegraaf
8ba9eb83af Implement flake8-async plugin (#4432) 2023-05-15 09:15:28 -04:00
Zanie Adkins
2c6efc2f5f Update C419 to be a suggested fix (#4424) 2023-05-15 10:30:40 +02:00
Ben Doerry
d6930ca991 Merge subsettings when extending configurations (#4431) 2023-05-15 02:34:58 +00:00
Yanks Yoon
f70c286e6a docs: update contributing guide (#4428) 2023-05-15 02:21:37 +00:00
Charlie Marsh
dcff515ad8 Make extend_function_names an Option type (#4434) 2023-05-15 02:15:02 +00:00
Jonathan Plasse
b9e387013f Fix RUF010 autofix within f-strings (#4423) 2023-05-15 02:08:30 +00:00
Charlie Marsh
a69451ff46 [pyupgrade] Remove keep-runtime-typing setting (#4427) 2023-05-14 03:12:52 +00:00
Tyler Yep
01b372a75c Implement flake8-future-annotations FA100 (#3979) 2023-05-14 03:00:06 +00:00
Charlie Marsh
cd2e7fa72a Use TextSize for flake8-todos Directive methods (#4426) 2023-05-13 22:05:51 -04:00
Charlie Marsh
fdf0b999cd Replace TODO tag regex with a lexer (#4413) 2023-05-13 15:23:46 +00:00
Jonathan Plasse
45b5fa573f Ignore ANN401 for overridden methods (#4409) 2023-05-13 15:20:04 +00:00
Jonathan Plasse
a0258f2205 [pylint] Fix PLW3301 auto-fix with generators (#4412) 2023-05-13 11:17:13 -04:00
alm
0a68636de3 [pylint] Add duplicate-bases rule (#4411) 2023-05-13 14:28:03 +00:00
Evan Rittenhouse
2f53781a77 Implement flake8_todos (#3921) 2023-05-13 14:19:06 +00:00
Micha Reiser
7e7be05ddf Upgrade dependencies (#4389) 2023-05-13 13:00:25 +00:00
Micha Reiser
f5afa8198c Use new rustpython_format crate over rustpython-common (#4388) 2023-05-13 12:35:02 +00:00
Charlie Marsh
eeabfd6d18 Enable autofix for split-assertions at top level (#4405) 2023-05-12 17:35:49 -04:00
Charlie Marsh
490301f9fe Replace macro_rules! visitors with dedicated methods (#4402) 2023-05-12 17:05:59 -04:00
Zanie Adkins
f5be3d8e5b Update CI to test Python wheel on Linux (#4398) 2023-05-12 16:27:18 -04:00
Charlie Marsh
7617519b4f Skip python -m ruff --help on linux-cross 2023-05-12 15:46:42 -04:00
Charlie Marsh
bc7ddd8f3a Temporarily create release on-tag 2023-05-12 15:31:48 -04:00
Charlie Marsh
e6bb5cddcf Add Astral badge to the repo (#4401) 2023-05-12 19:27:38 +00:00
Charlie Marsh
dcedd5cd9d Bump version to 0.0.267 (#4400) 2023-05-12 19:04:56 +00:00
konstin
606b6ac3df Workaround for maturin bug (#4399) 2023-05-12 18:55:55 +00:00
Zanie Adkins
ebda9b31d9 Update CI to test python -m ruff on release (#4397) 2023-05-12 18:47:30 +00:00
Lotem
52f6663089 Implement RUF010 to detect explicit type conversions within f-strings (#4387) 2023-05-12 18:12:58 +00:00
Charlie Marsh
a6176d2c70 Add PyTorch to user list (#4393) 2023-05-12 18:02:13 +00:00
OMEGA_RAZER
1d165f7e9d Add linting badge that can be used to display usage (#3938) 2023-05-12 17:58:29 +00:00
Charlie Marsh
e96092291d Update Ruff badge (#4392) 2023-05-12 13:42:33 -04:00
Charlie Marsh
67076b2dcb Bump version to 0.0.266 (#4391) 2023-05-12 13:11:03 -04:00
Charlie Marsh
7e3ba7f32a Use bitflags for tracking Context flags (#4381) 2023-05-12 16:07:26 +00:00
konstin
09dbd2029c Update maturin to maturin 0.15 (#3999)
* Update maturin to maturin>=0.14.17

This allows removing the deprecated `[package.metadata.maturin]`

* Update to maturin 0.15
2023-05-12 15:43:06 +02:00
Jonathan Plasse
1380bd94da Expose more fields in rule explanation (#4367) 2023-05-11 19:22:23 -04:00
Jonathan Plasse
c10a4535b9 Disallow unreachable_pub (#4314) 2023-05-11 18:00:00 -04:00
Charlie Marsh
97802e7466 Ignore some methods on list in flake8-boolean-trap (#4385) 2023-05-11 21:54:59 +00:00
Jonathan Plasse
4fd4a65718 Isolate show statistic integration test (#4383) 2023-05-11 21:42:34 +00:00
Charlie Marsh
d78c614764 Remove special-casing for flake8-builtins rules (#4380) 2023-05-11 16:39:28 -04:00
Charlie Marsh
3f3dd7af99 Move some recursion out of the pre-visit statement phase (#4379) 2023-05-11 15:46:25 -04:00
Charlie Marsh
871b92a385 Avoid re-using imports beyond current edit site (#4378) 2023-05-11 14:47:18 -04:00
Charlie Marsh
9158f13ee6 Respect __all__ imports when determining definition visibility (#4357) 2023-05-11 17:43:51 +00:00
Charlie Marsh
72e0ffc1ac Delay computation of Definition visibility (#4339) 2023-05-11 17:14:29 +00:00
Charlie Marsh
ffcf0618c7 Avoid underflow in expected-special-method-signature (#4377) 2023-05-11 12:47:47 -04:00
Micha Reiser
1ccef5150d Remove lifetime from FormatContext (#4376) 2023-05-11 15:43:42 +00:00
konstin
6a52577630 Ecosystem CI: Allow storing checkouts locally (#4192)
* Ecosystem CI: Allow storing checkouts locally

This adds a --checkouts options to (re)use a local directory instead of checkouts into a tempdir

* Fix missing path conversion
2023-05-11 17:36:44 +02:00
konstin
3c2f41b615 Also show rule codes in autofix errors in production codes (#4327)
I needed those changes for #4326
2023-05-11 17:36:03 +02:00
Calum Young
b76b4b6016 List rule changes in ecosystem (#4371)
* Count changes for each rule

* Handle case where rule matches were found in a line

* List and sort by changes

* Remove detail from rule changes

* Add comment about leading :

* Only print rule changes if rule changes are present

* Use re.search and match group

* Remove dict().items()

* Use match group to extract rule code
2023-05-11 16:33:15 +02:00
Jeong, YunWon
bbadbb5de5 Refactor code to use the new RustPython is method (#4369) 2023-05-11 16:16:36 +02:00
Calum Young
ba6370e5d0 Move black excludes from pre-commit config to pyproject.toml (#4370) 2023-05-11 09:00:05 -04:00
Jeong, YunWon
be6e00ef6e Re-integrate RustPython parser repository (#4359)
Co-authored-by: Micha Reiser <micha@reiser.io>
2023-05-11 07:47:17 +00:00
Charlie Marsh
865205d992 Implement pygrep-hook's Mock-mistake diagnostic (#4366) 2023-05-11 03:26:29 +00:00
Charlie Marsh
572adf7994 Use target name in hardcoded-password diagnostics (#4365) 2023-05-11 02:54:27 +00:00
Charlie Marsh
3b26bf84f5 Avoid debug panic with empty indent replacement (#4364) 2023-05-11 02:42:18 +00:00
Charlie Marsh
f4f88308ae Remove Copy and destructure Snapshot (#4358) 2023-05-10 19:46:18 +00:00
Charlie Marsh
ea3d3a655d Add a Snapshot abstraction for deferring and restoring visitor context (#4353) 2023-05-10 16:50:47 +00:00
Charlie Marsh
fd34797d0f Add a specialized StatementVisitor (#4349) 2023-05-10 12:42:20 -04:00
dependabot[bot]
6532455672 Bump json5 from 1.0.1 to 1.0.2 in /playground (#4354) 2023-05-10 16:34:37 +00:00
Charlie Marsh
257c571c43 Remove pub from some Checker fields (#4352) 2023-05-10 12:33:47 -04:00
Charlie Marsh
ccdee55e6e Tweak capitalization of B021 message (#4350) 2023-05-10 15:59:00 +00:00
Charlie Marsh
6d6d7abf70 Use short-import for HashMap (#4351) 2023-05-10 15:46:55 +00:00
konstin
0096938789 Optionally show fixes when using --features ecosystem_ci with cargo and --show-fixes at runtime (#4191)
* Generate fixes when using --show-fixes

Example command: `cargo run --bin ruff -- --no-cache --select F401
--show-source --show-fixes
crates/ruff/resources/test/fixtures/pyflakes/F401_9.py`

Before, `--show-fixes` was ignored:

```
crates/ruff/resources/test/fixtures/pyflakes/F401_9.py:4:22: F401 [*] `foo.baz` imported but unused
  |
4 | __all__ = ("bar",)
5 | from foo import bar, baz
  |                      ^^^ F401
  |
  = help: Remove unused import: `foo.baz`

Found 1 error.
[*] 1 potentially fixable with the --fix option.
```

After:

```
crates/ruff/resources/test/fixtures/pyflakes/F401_9.py:4:22: F401 [*] `foo.baz` imported but unused
  |
4 | __all__ = ("bar",)
5 | from foo import bar, baz
  |                      ^^^ F401
  |
  = help: Remove unused import: `foo.baz`

ℹ Suggested fix
1 1 | """Test: late-binding of `__all__`."""
2 2 |
3 3 | __all__ = ("bar",)
4   |-from foo import bar, baz
  4 |+from foo import bar

Found 1 error.
[*] 1 potentially fixable with the --fix option.
```

* Add `--format ecosystem-ci`

* cargo dev generate-all

* Put behind cargo feature

* Regenerate docs

* Don't test ecosystem_ci feature on CI

* Use top level flag instead

* Fix

* Simplify code based on #4191

* Remove old TODO comment
2023-05-10 17:45:57 +02:00
Micha Reiser
853d8354cb JSON Emitter: Use one indexed column numbers for edits (#4007)
I noticed in the byte-offsets refactor that the `JsonEmitter` uses one indexed column numbers for the diagnostic start and end locations but not for `edits`.

This PR changes the `JsonEmitter` to emit one-indexed column numbers for edits, as we already do for `Message::location` and `Message::end_location`.

## Open questions

~We'll need to change the LSP to subtract 1 from the columns in `_parse_fix`~

6e44fadf8a/ruff_lsp/server.py (L129-L150)

~@charliermarsh is there a way to get the ruff version in that method? If not, then I recommend adding a `version` that we increment whenever we make incompatible changes to the serialized message. We can then use it in the LSP to correctly compute the column offset.~

I'll use the presence of the `Fix::applicability` field to detect if the Ruff version uses one or zero-based column indices.

See https://github.com/charliermarsh/ruff-lsp/pull/103
2023-05-10 17:21:02 +02:00
Charlie Marsh
5f64d2346f Enforce max-doc-length for multi-line docstrings (#4347) 2023-05-10 11:06:07 -04:00
Micha Reiser
ddbe5a1243 Add Fix::applicability to JSON output (#4341) 2023-05-10 14:34:53 +00:00
Evan Rittenhouse
04097d194c Fix false positives in PD002 (#4337) 2023-05-10 16:04:28 +02:00
Micha Reiser
a2b8487ae3 Remove functor from autofix title (#4245) 2023-05-10 07:21:15 +00:00
Micha Reiser
8969ad5879 Always generate fixes (#4239) 2023-05-10 07:06:14 +00:00
Micha Reiser
bfa1c28c00 Use non-empty ranges for logical-lines diagnostics (#4133) 2023-05-10 06:44:33 +00:00
Zanie Adkins
cf7aa26aa4 Add Applicability to Fix (#4303)
Co-authored-by: Micha Reiser <micha@reiser.io>
2023-05-10 08:42:46 +02:00
Micha Reiser
d66ce76691 Truncate SyntaxErrors before newline character (#4124) 2023-05-10 08:37:57 +02:00
Tom Kuson
b8bb9e8b92 Add docs for flake8-simplify rules (#4334) 2023-05-10 03:03:24 +00:00
Charlie Marsh
5e46dcbf21 Handle .encode calls on parenthesized expressions (#4338) 2023-05-09 22:57:10 -04:00
trag1c
045449ab12 Improved E713 & E714 code examples (#4336) 2023-05-09 22:27:44 -04:00
Tom Kuson
d5ff8d7c43 Add flake8-pie documentation (#4332) 2023-05-09 22:11:30 +00:00
Charlie Marsh
d92fb11e80 Include positional- and keyword-only arguments in too-many-arguments (#4329) 2023-05-09 18:05:53 -04:00
Charlie Marsh
3d947196f8 Make violation struct fields private (#4331) 2023-05-09 18:00:20 -04:00
Charlie Marsh
e846f2688b Avoid SIM105 autofixes that would remove comments (#4330) 2023-05-09 21:30:56 +00:00
Charlie Marsh
7b91a162c6 Remove current_ prefix from some Context methods (#4325) 2023-05-09 19:40:12 +00:00
Charlie Marsh
8c2cfade90 Move show_source onto CLI settings group (#4317) 2023-05-09 17:26:25 +00:00
Charlie Marsh
a435c0df4b Remove deprecated update-check setting (#4313) 2023-05-09 13:10:02 -04:00
Aaron Cunningham
48e1852893 Revert the B027 autofix logic (#4310) 2023-05-09 13:08:20 -04:00
Calum Young
03f141f53d Check that all rules have descriptions (#4315) 2023-05-09 16:53:23 +00:00
Calum Young
8dea47afc1 Update mkdocs unformatted example error message (#4312) 2023-05-09 12:36:13 -04:00
Charlie Marsh
d3b71f1e04 Run autofix on initial watcher pass (#4311) 2023-05-09 12:35:32 -04:00
Mikko Leppänen
04e8e74499 Feat: detect changes also in configuration files (#4169) 2023-05-09 16:22:52 +00:00
konstin
318653c427 Write diagnostic name when failing to create fix (#4309) 2023-05-09 17:46:40 +02:00
Marti Raudsepp
f08fd5cbf0 Tweak package metadata URLs, add changelog and docs (#4304) 2023-05-09 11:32:47 -04:00
Micha Reiser
99a755f936 Add schemars feature (#4305) 2023-05-09 16:15:18 +02:00
Aurelio Jargas
e7dfb35778 UP011: Fix typo in rule description (#4306) 2023-05-09 08:49:15 -04:00
Dhruv Manilawala
085fd37209 Preserve whitespace around ListComp brackets in C419 (#4099) 2023-05-09 08:43:05 +02:00
Charlie Marsh
83536cf87b Ignore TRY301 exceptions without except handlers (#4301) 2023-05-09 03:38:02 +00:00
Charlie Marsh
9366eb919d Specify exact command in incorrect parentheses suggestion (#4300) 2023-05-09 02:21:54 +00:00
Charlie Marsh
8be51942dd Use ruff_python_semantic abstract utility in flake8-pytest-style (#4299) 2023-05-08 22:12:28 -04:00
Charlie Marsh
d365dab904 Include static and class methods in in abstract decorator list (#4298) 2023-05-08 21:54:02 -04:00
Charlie Marsh
f23851130a Add flynt to documentation (#4295) 2023-05-09 00:52:41 +00:00
Aarni Koskela
efdf383f5e Implement Flynt static string join transform as FLY002 (#4196) 2023-05-08 20:46:38 -04:00
Charlie Marsh
61f21a6513 Rewrite not not a as bool(a) in boolean contexts (#4294) 2023-05-08 23:38:24 +00:00
Charlie Marsh
43d6aa9173 Clarify some docstring-related docs (#4292) 2023-05-08 22:24:53 +00:00
Charlie Marsh
c54e48dce5 Avoid panics for f-string rewrites at start-of-file (#4291) 2023-05-08 19:44:57 +00:00
Charlie Marsh
b913e99bde Explicitly support ASCII-only for capitalization checks (#4290) 2023-05-08 15:41:11 -04:00
Dhruv Manilawala
4ac506526b Avoid D403 if first char cannot be uppercased (#4283) 2023-05-08 15:33:24 -04:00
Calum Young
cd41de2588 Check docs formatting check (#4270) 2023-05-08 19:03:22 +00:00
Dhruv Manilawala
3344d367f5 Avoid fixing PD002 in a lambda expression (#4286) 2023-05-08 18:24:27 +00:00
Aarni Koskela
d7a369e7dc Update confusable character mapping (#4274) 2023-05-08 14:20:44 -04:00
Jonathan Plasse
1b1788c8ad Fix replace_whitespace() tabulation to space (#4226)
Co-authored-by: Micha Reiser <micha@reiser.io>
2023-05-08 12:03:04 +00:00
Micha Reiser
4d5a339d9e Remove Fix::from(Edit) and add deprecated replacement methods to Diagnostics (#4275) 2023-05-08 10:25:50 +00:00
Zanie Adkins
0801f14046 Refactor Fix and Edit API (#4198) 2023-05-08 11:57:03 +02:00
Micha Reiser
edaf891042 Fix jemalloc page size on aarch64 (#4247)
Co-authored-by: konstin <konstin@mailbox.org>
2023-05-08 08:10:03 +02:00
Trevor McCulloch
3beff29026 [pylint] Implement nested-min-max (W3301) (#4200) 2023-05-07 03:14:14 +00:00
Jerome Leclanche
5ac2c7d293 Add .git-rewrite folder to default ignored folder paths (#4261) 2023-05-06 22:40:38 -04:00
Charlie Marsh
e66fdb83d0 Respect insertion location when importing symbols (#4258) 2023-05-07 02:32:40 +00:00
Charlie Marsh
a95bafefb0 Fix RET504 example in docs (#4260) 2023-05-06 16:56:52 -04:00
Charlie Marsh
539af34f58 Add a utility method to detect top-level state (#4259) 2023-05-06 20:24:27 +00:00
Charlie Marsh
983bb31577 Remove RefEquality usages from Context (#4257) 2023-05-06 15:55:14 -04:00
Charlie Marsh
b98b604071 Remove some deferred &Stmt references (#4256) 2023-05-06 18:42:35 +00:00
Charlie Marsh
cd27b39aff Re-order some code in scope.rs (#4255) 2023-05-06 16:36:20 +00:00
Charlie Marsh
a9fc648faf Use NodeId for Binding source (#4234) 2023-05-06 16:20:08 +00:00
Charlie Marsh
c1f0661225 Replace parents statement stack with a Nodes abstraction (#4233) 2023-05-06 16:12:41 +00:00
Dhruv Manilawala
2c91412321 Consider Flask app logger as logger candidate (#4253) 2023-05-06 11:31:10 -04:00
Charlie Marsh
11e1380df4 Bump version to 0.0.265 (#4248) 2023-05-05 13:16:05 -04:00
Micha Reiser
e93f378635 Refactor whitespace around operator (#4223) 2023-05-05 09:37:56 +02:00
Micha Reiser
2124feb0e7 Fail lint tests if the fix creates a syntax error (#4202) 2023-05-05 07:59:33 +02:00
Charlie Marsh
c0e7269b07 Update doc defaults for section-order (#4232) 2023-05-04 21:35:27 +00:00
Chris Chan
c2921e957b [pylint] Implement import-self (W0406) (#4154) 2023-05-04 16:05:15 -04:00
Charlie Marsh
93cfce674a Ignore __debuggerskip__ in unused variable checks (#4229) 2023-05-04 15:45:49 -04:00
Charlie Marsh
b71cc3789f Change --fix-only exit semantics to mirror --fix (#4146) 2023-05-04 19:03:15 +00:00
Zanie Adkins
717128112d Fix panic in pydocstyle D214 when docstring indentation is empty (#4216) 2023-05-04 14:42:34 -04:00
Arya Kumar
e9e194ab32 [flake8-pyi] Implement PYI042 and PYI043 (#4214) 2023-05-04 14:35:26 -04:00
Calum Young
890e630c41 Allow linking to individual rules (#4158) 2023-05-04 13:43:53 -04:00
Aaron Cunningham
d78287540d Update B027 to support autofixing (#4178) 2023-05-04 16:36:32 +00:00
Charlie Marsh
494e807315 Add space when joining rule codes for debug messages (#4225) 2023-05-04 15:34:34 +00:00
Tom Kuson
6db1a32eb9 Add docs for PLC rules (#4224) 2023-05-04 10:56:00 -04:00
Dhruv Manilawala
bb2cbf1f25 End of statement insertion should occur after newline (#4215) 2023-05-04 16:17:41 +02:00
konstin
badfdab61a Show rule codes on autofix failure (#4220) 2023-05-04 15:25:07 +02:00
Dhruv Manilawala
59d40f9f81 Show settings path in --show-settings output (#4199) 2023-05-04 08:22:31 +02:00
Arya Kumar
37aae666c7 [flake8-pyi] PYI020 (#4211) 2023-05-03 22:37:32 -04:00
Leiser Fernández Gallo
460023a959 Fix era panic caused by out of bound edition (#4206) 2023-05-03 15:48:43 +02:00
Aarni Koskela
d0e3ca29d9 Print out autofix-broken or non-converging code when debugging (#4201) 2023-05-03 13:50:03 +02:00
Christian Clauss
ccfc78e2d5 faq: Clarify how Ruff and Black treat line-length. (#4180) 2023-05-02 23:19:38 +00:00
Micha Reiser
b14358fbfe Render tabs as 4 spaces in diagnostics (#4132) 2023-05-02 13:14:02 +00:00
wookie184
ac600bb3da Warn on PEP 604 syntax not in an annotation, but don't autofix (#4170) 2023-05-01 23:49:20 -07:00
Charlie Marsh
8cb76f85eb Bump version to 0.0.264 (#4179) 2023-05-01 23:33:38 -07:00
Charlie Marsh
56c45013c2 Allow boolean parameters for pytest.param (#4176) 2023-05-02 01:07:50 +00:00
Calum Young
a4ce746892 Reference related settings in rules (#4157) 2023-05-02 00:59:00 +00:00
Calum Young
2d6d51f3a1 Add flake8-return docs (#4164) 2023-05-02 00:53:46 +00:00
Jonathan Plasse
814731364a Fix UP032 auto-fix (#4165) 2023-04-30 16:57:41 -04:00
Jonathan Plasse
8c97e7922b Fix F811 false positive with match (#4161) 2023-04-30 14:39:45 -04:00
Jonathan Plasse
a32617911a Use --filter=blob:none to clone CPython faster (#4156) 2023-04-30 13:39:22 +02:00
Charlie Marsh
64b7280eb8 Respect parent-scoping rules for NamedExpr assignments (#4145) 2023-04-29 22:45:30 +00:00
Evan Rittenhouse
8d64747d34 Remove pyright comment prefix from PYI033 checks (#4152) 2023-04-29 18:41:04 -04:00
Charlie Marsh
2115d99c43 Remove ScopeStack in favor of child-parent ScopeId pointers (#4138) 2023-04-29 18:23:51 -04:00
Calum Young
39ed75f643 Document flake8-unused-arguments (#4147) 2023-04-29 19:17:50 +00:00
Calum Young
8f61eae1e7 Add remaining pep8-naming docs (#4149) 2023-04-29 15:13:10 -04:00
Calum Young
f0f4bf2929 Move typos to pre-commit config (#4148) 2023-04-29 12:13:35 -04:00
Calum Young
03144b2fad Document flake8-commas (#4142) 2023-04-29 03:24:15 +00:00
Calum Young
0172cc51a7 Document flake8-print (#4144) 2023-04-29 03:19:00 +00:00
Calum Young
12d64a223b Document RUF100 (#4141) 2023-04-28 22:14:15 +00:00
Charlie Marsh
432ea6f2e2 Tweak rule documentation for B008 (#4137) 2023-04-28 01:29:03 +00:00
Evan Rittenhouse
b34804ceb5 Make D410/D411 autofixes mutually exclusive (#4110) 2023-04-28 01:24:35 +00:00
Moritz Sauter
ee6d8f7467 Add bugbear immutable functions as allowed in dataclasses (#4122) 2023-04-27 21:23:06 -04:00
Dhruv Manilawala
089b64e9c1 Autofix EM101, EM102, EM103 if possible (#4123) 2023-04-27 18:53:27 +00:00
Tom Kuson
3e81403fbe Add pygrep-hooks documentation (#4131) 2023-04-27 18:33:07 +00:00
Charlie Marsh
3c9f5e2fdc Preserve star-handling special-casing for force-single-line (#4129) 2023-04-27 00:02:17 -04:00
Micha Reiser
17db2e2a62 Fix B023 shadowed variables in nested functions (#4111) 2023-04-26 22:01:31 +01:00
Micha Reiser
e04ef42334 Use memchr to speedup newline search on x86 (#3985) 2023-04-26 20:15:47 +01:00
Micha Reiser
f3e6ddda62 perf(logical-lines): Various small perf improvements (#4022) 2023-04-26 20:10:35 +01:00
Micha Reiser
cab65b25da Replace row/column based Location with byte-offsets. (#3931) 2023-04-26 18:11:02 +00:00
Charlie Marsh
ee91598835 Tweak --show-fixes documentation (#4117) 2023-04-26 15:15:56 +00:00
Calum Young
ab65eaea7f Add docs build validation stage to CI (#4116)
Nice. Thank you
2023-04-26 14:57:59 +01:00
konstin
19d8913e32 Use musl in ecosystem docker (#3998)
This prevents errors when the host glibc is newer than the one in the docker container
2023-04-26 05:54:53 +02:00
Dhruv Manilawala
b9c06b48e1 Document that --diff implies --fix-only (#4098) 2023-04-25 21:19:44 -06:00
Charlie Marsh
7266eb0d69 Add support for providing command-line arguments via argfile (#4087) 2023-04-25 17:58:21 -06:00
Jonathan Plasse
4df7bc0bcd Fix E713 and E714 false positives for multiple comparisons (#4083) 2023-04-25 11:37:56 -06:00
Calum Young
464a0ff483 Fix docs failure (#4097) 2023-04-25 11:30:37 -06:00
Charlie Marsh
fd7ccb4c9e Bump version to 0.0.263 (#4086) 2023-04-24 23:32:29 -06:00
Evan Rittenhouse
ae6f38344a Unify positional and keyword arguments when checking for missing arguments in docstring (#4067) 2023-04-25 05:32:15 +00:00
Trevor McCulloch
bbf658d4c5 [pylint] Implement PLE0302 unexpected-special-method-signature (#4075) 2023-04-25 04:51:21 +00:00
Jonathan Plasse
1f3b0fd602 Fix SIM222 and SIM223 false positives and auto-fix (#4063) 2023-04-25 04:44:02 +00:00
Dhruv Manilawala
37483f3ac9 Ignore ClassVar annotation for RUF008, RUF009 (#4081) 2023-04-24 23:58:30 +00:00
Zanie Adkins
4d3a1e0581 Add PrefectHQ/prefect to list of ruff users (#4084) 2023-04-24 17:49:12 -06:00
Bartosz Sokorski
9e5f348a17 Add Poetry to the list of projects using Ruff (#4085) 2023-04-24 17:48:35 -06:00
Jonathan Plasse
5e91211e6d Add in_boolean_test to Context (#4072) 2023-04-23 23:18:23 -06:00
Jonathan Plasse
df77595426 Move Truthiness into ruff_python_ast (#4071) 2023-04-24 04:54:31 +00:00
Charlie Marsh
407af6e0ae Avoid infinite-propagation of inline comments when force-splitting imports (#4074) 2023-04-23 22:39:51 -06:00
Dhruv Manilawala
d64146683e Increment priority should be (branch-local, global) (#4070) 2023-04-23 00:04:15 -06:00
Charlie Marsh
0e7914010f Misc. small clean-up of flake8-import-conventions rules (#4069) 2023-04-23 04:57:15 +00:00
Edgar R. M
cfc7d8a2b5 [flake8-import-conventions] Implement new rule ICN003 to ban from ... import ... for selected modules (#4040) 2023-04-23 04:40:36 +00:00
Tom Kuson
f5cd659292 Add docs for tryceratops rules (#4042) 2023-04-23 04:35:56 +00:00
Charlie Marsh
260138b427 Use Context for pep8-naming helpers (#4068) 2023-04-22 18:44:54 -04:00
Jonathan Plasse
2da149fd7e Ignore N815 for TypedDict fields (#4066) 2023-04-22 18:17:14 -04:00
Micha Reiser
e33887718d Use Rust 1.69 (#4065) 2023-04-22 23:04:17 +01:00
Micha Reiser
ba4f4f4672 Upgrade dependencies (#4064) 2023-04-22 18:04:01 +01:00
Pronoy Mandal
b7a57ce120 Update tutorial.md (#4055) 2023-04-21 10:56:31 -06:00
Alan Du
82abbc7234 [flake8-bugbear] Add pytest.raises(Exception) support to B017 (#4052) 2023-04-21 03:43:01 +00:00
Dhruv Manilawala
ba98149022 Avoid RUF008 if field annotation is immutable (#4039) 2023-04-20 16:02:12 -04:00
Dhruv Manilawala
7fd44a3e12 Avoid PYI015 for valid default value without annotation (#4043) 2023-04-20 15:45:47 -04:00
Evan Rittenhouse
6e8d561090 Support --fix in watch mode (#4035) 2023-04-19 23:33:12 -04:00
Jacob Coffee
cb762f4cad Add Astral announcement to README (#4010) 2023-04-19 20:28:45 +00:00
Charlie Marsh
eed6866b7e Add relative-path tests for banned-api (#4033) 2023-04-19 16:04:22 -04:00
Charlie Marsh
25a6bfa9ee Bump version to 0.0.262 (#4032) 2023-04-19 15:49:28 -04:00
Charlie Marsh
b3f8f2a5c1 Remove TODO in handle_node_store (#4031) 2023-04-19 15:28:56 -04:00
Charlie Marsh
cc8b5a543b Ignore stub file assignments to value-requiring targets (#4030) 2023-04-19 15:26:00 -04:00
Charlie Marsh
10d5415bcb Ignore certain flake8-pyi errors within function bodies (#4029) 2023-04-19 15:10:29 -04:00
Charlie Marsh
827cbe7f97 Treat non-future function annotations as required-at-runtime (#4028) 2023-04-19 14:43:55 -04:00
Charlie Marsh
0d84517fbc Use module path resolver for relative autofix (#4027) 2023-04-19 14:43:45 -04:00
Charlie Marsh
7fa1da20fb Support relative imports in banned-api enforcement (#4025) 2023-04-19 14:30:13 -04:00
Francesco Nuzzo
f13a161ead remove unnecessary f-string formatting (#4026) 2023-04-19 18:14:33 +00:00
Charlie Marsh
c4cda301aa Ignore relative imports in banned-api rules (#4024) 2023-04-19 13:30:08 -04:00
Charlie Marsh
13fda30051 Refactor flake8_tidy_imports rules to consistently take Checker (#4023) 2023-04-19 16:42:15 +00:00
Micha Reiser
a3146ab1ca Fix (doc-)line-too-long start location (#4006) 2023-04-19 08:42:28 +02:00
Micha Reiser
c0cf87356e Set non-empty range for indentation diagnostics (#4005) 2023-04-18 16:26:13 +02:00
Andrei Grazhdankov
6c3e4ef441 Add Robyn to user list (#4008) 2023-04-18 09:51:20 -04:00
Charlie Marsh
6c038830a8 Ignore argument assignments when enforcing RET504 (#4004) 2023-04-18 03:22:38 +00:00
Charlie Marsh
064a293b80 Fix defaults for section-order (#4003) 2023-04-18 03:00:17 +00:00
Charlie Marsh
79c47e29ee Avoid short-circuiting when detecting RET rules (#4002) 2023-04-17 22:52:26 -04:00
Charlie Marsh
be87a29a9d Respect typing-modules when evaluating no-return functions (#4001) 2023-04-17 20:25:44 +00:00
Micha Reiser
280dffb5e1 Add parser benchmark (#3990) 2023-04-17 16:43:59 +02:00
Charlie Marsh
336993ea06 Change Alpha trove classifier to Beta (#3995) 2023-04-17 13:55:49 +00:00
Tom Kuson
516cb10000 Add more documentation for flake8-type-checking (#3994) 2023-04-17 09:51:54 -04:00
Charlie Marsh
1cdd5e3424 Remove autofix behavior for uncapitalized-environment-variables (SIM112) (#3988) 2023-04-16 23:19:05 +00:00
Dhruv Manilawala
bd78c6ade2 Preserve type annotations when fixing E731 (#3983) 2023-04-16 23:15:38 +00:00
Dhruv Manilawala
5ce35faa86 Do not consider nested comment as part of code (#3984) 2023-04-16 19:11:01 -04:00
Justin Chu
484b572e6b Add ONNX Runtime to user list (#3982) 2023-04-16 18:21:46 -04:00
Charlie Marsh
81805a45f0 Add some additional users (#3975) 2023-04-14 12:41:22 -04:00
Charlie Marsh
c457752f36 Redirect PIE802 to C419 (#3971) 2023-04-13 22:12:32 -04:00
Charlie Marsh
289289bfd3 Implement unnecessary-literal-within-dict-call (C418) (#3969) 2023-04-14 01:39:35 +00:00
Charlie Marsh
09274307e8 Add multi-edit change to BREAKING_CHANGES.md (#3968) 2023-04-13 23:12:00 +00:00
Charlie Marsh
d8718dcf54 Remove extraneous debug and TODO (#3967) 2023-04-13 18:45:18 -04:00
Charlie Marsh
fb9eeba422 Move user-defined section validation into Settings (#3966) 2023-04-13 22:40:05 +00:00
Paul
2d2630ef07 Implement isort custom sections and ordering (#2419) (#3900) 2023-04-13 21:28:22 +00:00
Charlie Marsh
1f22e035e3 Add 'or if cond' to E712 message (#3962) 2023-04-13 19:02:23 +00:00
Rob Young
a6a7584d79 Implement flake8-bandit shell injection rules (#3924) 2023-04-13 14:45:27 -04:00
Charlie Marsh
ffac4f6ec3 Ignore assert errors (S101) in TYPE_CHECKING blocks (#3960) 2023-04-13 18:20:44 +00:00
Dhruv Manilawala
032a84b167 Check for parenthesis in implicit str concat in PT006 (#3955) 2023-04-13 17:56:18 +00:00
Charlie Marsh
3357aaef4b Add docs for assert rule (S101) (#3959) 2023-04-13 13:43:00 -04:00
Charlie Marsh
d9ed43d112 Clarify some isort differences in FAQ (#3954) 2023-04-13 04:05:28 +00:00
Charlie Marsh
e160a52bfd Raise percent-format upgrade rule (UP031) for hanging modulos (#3953) 2023-04-12 23:59:20 -04:00
Charlie Marsh
9067ae47d1 Allow typing_extensions.TypeVar assignments in .pyi files (#3951) 2023-04-12 17:30:15 -04:00
Charlie Marsh
71e807b3be Add Prefect to user list (#3949) 2023-04-12 12:09:36 -04:00
Charlie Marsh
1e2df07544 Use identifier range for pytest rules (#3948) 2023-04-12 15:28:25 +00:00
USER-5
860841468c [flake8-pyi] Implement duplicate types in unions (PYI016) (#3922) 2023-04-12 04:06:09 +00:00
Charlie Marsh
ed4ecc3255 Remove unused import (#3944) 2023-04-12 03:55:38 +00:00
Charlie Marsh
b999e4b1e2 Allow users to extend the set of included files via include (#3914) 2023-04-11 23:39:43 -04:00
Charlie Marsh
8ce227047d Tidy up some pygrep-hooks rules (#3942) 2023-04-12 03:35:15 +00:00
Daniel Stancl
523515f936 [flake8-import-conventions] Add a rule for BannedImportAlias (#3926) 2023-04-12 03:29:24 +00:00
Charlie Marsh
10da3bc8dd Support pyright: ignore comments (#3941) 2023-04-12 03:10:29 +00:00
Charlie Marsh
eb0dd74040 Avoid adding required imports to stub files (#3940) 2023-04-11 22:31:20 -04:00
Micha Reiser
61200d2171 lint snapshots: Use filename only to avoid platform specific separators (#3930) 2023-04-11 11:40:51 +02:00
Micha Reiser
e8aebee3f6 Pretty print Diagnostics in snapshot tests (#3906) 2023-04-11 09:03:00 +00:00
Micha Reiser
210083bdd8 Order Edits by Locations (#3905) 2023-04-11 08:56:41 +00:00
Micha Reiser
c33c9dc585 Introduce SourceFile to avoid cloning the message filename (#3904) 2023-04-11 08:28:55 +00:00
Micha Reiser
056c212975 Render code frame with context (#3901) 2023-04-11 10:22:11 +02:00
Micha Reiser
381203c084 Store source code on message (#3897) 2023-04-11 07:57:36 +00:00
Micha Reiser
76c47a9a43 Cheap cloneable LineIndex (#3896) 2023-04-11 07:33:40 +00:00
Micha Reiser
9209e57c5a Extract message emitters from Printer (#3895) 2023-04-11 07:24:25 +00:00
Leiser Fernández Gallo
333f1bd9ce Extend SIM105 to match also 'Ellipsis only' bodies in exception handlers (#3925) 2023-04-10 09:55:02 -04:00
Leiser Fernández Gallo
002caadf9e [flake8-simplify] Add autofix for contextlib.suppress (SIM105) (#3915) 2023-04-09 22:45:19 +00:00
Dhruv Manilawala
311ba29d0f Do not skip analysis if *args present for F523 (#3923) 2023-04-09 18:34:52 -04:00
Dhruv Manilawala
237a64d922 Check for arguments in inner/outer call for C414 (#3916) 2023-04-09 18:33:11 -04:00
Moritz Sauter
d4af2dd5cf [ruff] Add checks for mutable defaults in dataclasses (#3877) 2023-04-09 02:46:28 +00:00
Charlie Marsh
a36ce585ce Remove extract_path_names helper (#3920) 2023-04-08 11:14:42 -04:00
Charlie Marsh
29ec6df24f Avoid N802 violations for @override methods (#3912) 2023-04-08 03:11:50 +00:00
Evan Rittenhouse
8b17508ef1 Remove old documentation (#3911) 2023-04-07 22:51:19 -04:00
Evan Rittenhouse
abaf0a198d Ensure that tab characters aren't in multi-line strings before throwing a violation (#3837) 2023-04-06 22:25:40 -04:00
konstin
454c6d9c2f Extended ecosystem check with scraped data (#3858) 2023-04-06 22:39:48 +00:00
konstin
cae5503e34 [pylint] Fix unicode handling in PLE2515 (#3898) 2023-04-06 13:54:52 -04:00
Dhruv Manilawala
34e9786a41 Visit comprehension to detect group name usage/overrides (#3887) 2023-04-05 18:03:11 -04:00
Dhruv Manilawala
5467d45dfa Ignore PLW2901 when using typing cast (#3891) 2023-04-05 18:02:32 -04:00
Charlie Marsh
ac87137c1c Avoid printing docs on cargo dev generate-all (#3890) 2023-04-05 14:18:33 -04:00
Charlie Marsh
e0bccfd2d9 Allow legacy C and T selectors in JSON schema (#3889) 2023-04-05 17:58:36 +00:00
Tom Kuson
7b6e55a2e0 Add documentation for flake8-type-checking (#3886) 2023-04-05 17:30:25 +00:00
brucearctor
5c374b5793 Consistent Style/Levels in Usage (#3884) 2023-04-05 03:06:43 +00:00
Edgar R. M
ffdd0de522 Add Meltano to users (#3883) 2023-04-04 23:05:53 -04:00
Charlie Marsh
5370968839 Add some additional users and alphabetize (#3882) 2023-04-05 02:40:02 +00:00
Charlie Marsh
255b094b33 Bump version to 0.0.261 (#3881) 2023-04-04 22:31:01 -04:00
Dhruv Manilawala
b6155232ac Consider logger candidate from logging module only (#3878) 2023-04-04 19:52:57 +00:00
kyoto7250
390d7dcf39 Supports more cases in SIM112 (#3876) 2023-04-04 15:49:24 -04:00
Charlie Marsh
251340a246 Add LangChain and LlamaIndex (#3879) 2023-04-04 19:36:31 +00:00
Charlie Marsh
d919adc13c Introduce a ruff_python_semantic crate (#3865) 2023-04-04 16:50:47 +00:00
kyoto7250
46bcb1f725 [flake8-simplify] Implement dict-get-with-none-default (SIM910) (#3874) 2023-04-04 03:52:10 +00:00
Dhruv Manilawala
2b21effa77 fixup! Support mutually exclusive branches for B031 (#3844) (#3875) 2023-04-03 23:34:11 -04:00
Chris Chan
10504eb9ed Generate ImportMap from module path to imported dependencies (#3243) 2023-04-04 03:31:37 +00:00
Dhruv Manilawala
76e111c874 Support mutually exclusive branches for B031 (#3844) 2023-04-04 02:33:17 +00:00
brucearctor
e006b922a6 Add documentation for ruff-action (GitHub Action!) (#3857) 2023-04-03 23:47:26 +00:00
Charlie Marsh
60f6a8571a Allow starred arguments in B030 (#3871) 2023-04-03 23:20:34 +00:00
Charlie Marsh
f4173b2a93 Move shadow tracking into Scope directly (#3854) 2023-04-03 15:33:44 -04:00
Charlie Marsh
449e08ed08 Rename autofix::helpers to autofix::actions (#3866) 2023-04-03 13:34:49 -04:00
Charlie Marsh
5625410936 Remove uses_magic_variable_access dependence on Checker (#3864) 2023-04-03 12:22:06 -04:00
Charlie Marsh
3744e9ab3f Remove contains_effect's dependency on Context (#3855) 2023-04-03 12:08:13 -04:00
Nicolas Vuillamy
b52cb93e58 Add thank you in README.md + usage in MegaLinter (#3848) 2023-04-03 15:45:25 +00:00
Nazia Povey
849091d846 When checking module visibility, don't check entire ancestry (#3835) 2023-04-03 11:38:41 -04:00
Ran Benita
d2f2544f6e flake8-pyi: fix PYI015 false positive on assignment of TypeVar & friends (#3861) 2023-04-03 11:28:46 -04:00
Charlie Marsh
25771cd4b9 Use references for Export binding type (#3853) 2023-04-03 15:26:42 +00:00
Charlie Marsh
924bebbb4a Change "indexes" to "indices" in various contexts (#3856) 2023-04-02 23:08:03 +00:00
Charlie Marsh
08e5b3fa61 Make collect_call_path return an Option (#3849) 2023-04-01 22:29:32 -04:00
Charlie Marsh
d822e08111 Move CallPath into its own module (#3847) 2023-04-01 11:25:04 -04:00
Charlie Marsh
2f90157ce2 Move logging resolver into logging.rs (#3843) 2023-04-01 03:50:44 +00:00
Charlie Marsh
88308ef9cc Move Binding structs out of scope.rs (#3842) 2023-03-31 23:49:48 -04:00
Charlie Marsh
6d80c79bac Combine operations.rs and helpers.rs (#3841) 2023-04-01 03:40:34 +00:00
Charlie Marsh
2fbc620ad3 Move __all__ utilities to all.rs (#3840) 2023-04-01 03:31:15 +00:00
Charlie Marsh
27e40e9b31 Remove helpers.rs dependency on Binding (#3839) 2023-04-01 03:19:45 +00:00
Charlie Marsh
b6276e2d95 Move f-string identification into rule module (#3838) 2023-03-31 23:10:11 -04:00
Charlie Marsh
66d72b1c7b Move keyword checks into is_identifier (#3834) 2023-03-31 16:56:33 -04:00
Jonathan Plasse
968c7df770 Fix is_module_name() and improve perf of is_identifier() (#3795) 2023-03-31 15:15:36 -04:00
Jonathan Plasse
fe38597279 Fix SIM222 and SIM223 false positive (#3832) 2023-03-31 14:50:35 -04:00
Jonathan Plasse
f3f9a9f297 Fix pre-commit CI job exit code (#3833) 2023-03-31 14:47:04 -04:00
Micha Reiser
48d8680e71 Ambiguous unicode, only test unicode characters (#3814) 2023-03-31 18:03:00 +01:00
Charlie Marsh
82584ad101 Extend unncessary-generator-any-all to set comprehensions (#3824) 2023-03-31 16:29:25 +00:00
konstin
13e52b1f76 Use cache in cargo udeps CI (#3809) 2023-03-31 11:07:14 -04:00
Charlie Marsh
dfc872c9a0 Track star imports on Scope directly (#3822) 2023-03-31 15:01:12 +00:00
Charlie Marsh
cf7e1ddd08 Remove some usize references (#3819) 2023-03-30 17:35:42 -04:00
Charlie Marsh
9de1f82658 Avoid unnecessary-comprehension-any-all for async generators (#3823) 2023-03-30 18:43:59 +00:00
Charlie Marsh
54ad9397e5 Flag non-Name expressions in duplicate-isinstance-call (#3817) 2023-03-30 12:19:53 -04:00
Jonathan Plasse
29c8b75fd4 Ignore collapsible-if violations for if False: and if True: (#3732) 2023-03-30 15:52:43 +00:00
Charlie Marsh
0b586d5451 Use panic instead of unreachable for invalid arguments (#3816) 2023-03-30 15:40:53 +00:00
Charlie Marsh
01357f62e5 Add import insertion support to autofix capabilities (#3787) 2023-03-30 15:33:46 +00:00
Micha Reiser
d7113d3995 refactor: StateMachine use match statement (#3811) 2023-03-30 15:55:54 +02:00
Madison Swain-Bowden
a142d71e0b Add Openverse to users of ruff in README (#3806) 2023-03-30 09:14:47 -04:00
Charlie Marsh
f79506f5a4 Move some generic structs out of isort (#3788) 2023-03-30 08:58:01 -04:00
Dhruv Manilawala
44ae3237b8 Additional simple magic return types (#3805) 2023-03-30 08:57:49 -04:00
konstin
f4cda31708 Use crates.io version of pep440_rs (#3812)
* Use crates.io version of pep440_rs

* Update Cargo.lock
2023-03-30 12:47:07 +00:00
Charlie Marsh
4328448a2f Use multi-fix semantics for inplace removal (#3804) 2023-03-30 00:16:43 +00:00
Charlie Marsh
88298759ce Misc. follow-up changes to #3802 (#3803) 2023-03-29 19:18:36 -04:00
Charlie Marsh
3c0e789b19 Improve robustness of argument removal for encode calls (#3802) 2023-03-29 23:07:13 +00:00
Charlie Marsh
8601dcc09b Add import name resolution to Context (#3777) 2023-03-29 21:47:50 +00:00
Charlie Marsh
134fdd1609 Remove star-import handling from sys-exit-alias (#3776) 2023-03-29 21:33:50 +00:00
Charlie Marsh
2e6eddc7bd Improve top-of-file insertions for required imports (#3779) 2023-03-29 21:25:39 +00:00
Jonathan Plasse
cb588d1d6d Allow TID252 to fix all valid module paths (#3796) 2023-03-29 15:13:12 -04:00
Charlie Marsh
9d3b8eb67b Bump version to v0.0.260 (#3799) 2023-03-29 14:51:50 -04:00
Charlie Marsh
e1e5532ab1 Add flymake-ruff to docs (#3800) 2023-03-29 18:48:59 +00:00
Andy Freeland
7d962bf80c [flake8-bugbear] Allow pathlib.Path() in B008 (#3794) 2023-03-29 15:42:43 +00:00
Micha Reiser
595cd065f3 Reduce explcit clones (#3793) 2023-03-29 15:15:14 +02:00
Anže Starič
b6f1fed424 [isort]: support submodules in known_(first|third)_party config options (#3768) 2023-03-29 03:53:38 +00:00
Jonathan Plasse
5501fc9572 Exempt return with side effects for TRY300 (#3780) 2023-03-28 19:52:05 -04:00
Charlie Marsh
5977862a60 Enumerate all codes in default configuration example (#3790) 2023-03-28 23:36:22 +00:00
Leiser Fernández Gallo
224e85c6d7 Implement flake8-gettext (#3785) 2023-03-28 23:32:02 +00:00
Charlie Marsh
515e436cfa Clarify order of pre-commit hooks (#3789) 2023-03-28 23:15:36 +00:00
Charlie Marsh
f322bcd2bd Minor nits on reference names (#3786) 2023-03-28 22:18:19 +00:00
Charlie Marsh
22d5b0071d Rename end_of_statement to end_of_last_statement (#3775) 2023-03-28 12:31:06 -04:00
Charlie Marsh
990b378c4d Set parents even in same-line cases (#3773) 2023-03-28 12:09:30 -04:00
Charlie Marsh
e88fbae926 Use import alias locations for pep8-naming import rules (#3772) 2023-03-28 11:41:23 -04:00
Charlie Marsh
81de3a16bc Include with statements in complexity calculation (#3771) 2023-03-28 15:20:22 +00:00
Andy Freeland
bfecf684ce [flake8-bugbear] Add more immutable functions for B008 (#3764) 2023-03-28 10:50:05 -04:00
konstin
756e9956a2 Fix cargo test --doc (#3766) 2023-03-28 11:36:07 +00:00
Micha Reiser
f68c26a506 perf(pycodestyle): Initialize Stylist from tokens (#3757) 2023-03-28 11:53:35 +02:00
Micha Reiser
000394f428 perf(pycodestyle): Introduce TokenKind (#3745) 2023-03-28 11:22:39 +02:00
Micha Reiser
2fdf98ef4e perf(pycodestyle): Refactor checks to iterate over tokens insteadof text (#3736) 2023-03-28 10:37:13 +02:00
Micha Reiser
1d724b1495 perf(pycodestyle): Remove regex captures (#3735) 2023-03-28 09:50:34 +02:00
Micha Reiser
113a8b8fda perf(pycodestyle): Reduce allocations when computing logical lines (#3715) 2023-03-28 09:09:27 +02:00
Charlie Marsh
c3917eab38 Revert "Implement flake8-i18n (#3741)" (#3765) 2023-03-27 21:14:38 +00:00
JBLDSKY
0eb5a22dd1 [flake8-pyi] Implement PYI012 (#3743) 2023-03-27 18:27:24 +00:00
Charlie Marsh
450c6780ff Avoid useless-import alias (C0414) in .pyi files (#3761) 2023-03-27 18:27:03 +00:00
Leiser Fernández Gallo
5cb120327c Implement flake8-i18n (#3741) 2023-03-27 18:03:39 +00:00
trag1c
8dbffb576d Removed unnecessary pipe escape (#3760) 2023-03-27 13:49:47 -04:00
Charlie Marsh
31fff4b10e Disallow some restriction lints (#3754) 2023-03-26 23:20:20 +00:00
Jonathan Plasse
2326335f5c Improve performance of statistics (#3751) 2023-03-26 18:46:44 -04:00
Charlie Marsh
6ed6da3e82 Move fix::FixMode to flags::FixMode (#3753) 2023-03-26 21:40:06 +00:00
Jonathan Plasse
cd75b57036 Sort statistics by count (#3748) 2023-03-26 16:45:35 -04:00
Charlie Marsh
e603382cf0 Allow diagnostics to generate multi-edit fixes (#3709) 2023-03-26 16:45:19 -04:00
Charlie Marsh
32be63fd1e Avoid overlong-line errors for lines that end with URLs (#3663) 2023-03-26 18:17:35 +00:00
Jonathan Plasse
d594179275 Fix SIM222 and SIM223 false negatives (#3740) 2023-03-26 18:09:11 +00:00
Agriya Khetarpal
c0befb4670 Use wild::args() and add wild as a dependency (#3739) 2023-03-26 14:32:45 +00:00
Charlie Marsh
a66481ed28 Rename setter methods on Diagnostic (#3738) 2023-03-26 10:28:30 -04:00
Charlie Marsh
5c7898124f Traverse over nested string type annotations (#3724) 2023-03-25 21:56:09 -04:00
Jonathan Plasse
50a7916e84 [pydocstyle] Implement autofix for D403 (#3731) 2023-03-25 19:21:45 +00:00
Charlie Marsh
6a40a5c5a2 Add a note on src (#3733) 2023-03-25 16:18:34 +00:00
Jonathan Plasse
fec4fa39a7 Improve add_rule.py and add_plugin.py scripts (#3725) 2023-03-25 16:05:39 +00:00
Dhruv Manilawala
2659336ed1 Add support for .log(level, msg) calls in flake8-logging-format (#3726) 2023-03-25 15:55:53 +00:00
Jonathan Plasse
8ac7584756 [flake8-pyi] Implement PYI015 (#3728) 2023-03-25 15:48:11 +00:00
Jonathan Plasse
4a1740a4c4 [flake8-pyi] Add autofix for PYI014 (#3729) 2023-03-25 15:41:11 +00:00
Charlie Marsh
2083134a96 Rename Fix to Edit (#3702) 2023-03-24 19:29:14 -04:00
Charlie Marsh
c721eedc37 Remove 'b lifetime from Checker (#3723) 2023-03-24 21:42:18 +00:00
Dhruv Manilawala
c1d89d8c93 [flake8-bugbear]: Implement rule B031 (#3680) 2023-03-24 17:26:11 -04:00
Jonathan Plasse
b8ae1e0e05 Add pre-commit in CI (#3707) 2023-03-24 17:20:13 -04:00
Dhruv Manilawala
63adf9f5e8 Allow aliased logging module as a logger candidate (#3718) 2023-03-24 17:19:09 -04:00
Micha Reiser
7af83460ce Use unicode-width to determine line-length instead of character count (#3714) 2023-03-24 17:17:05 -04:00
Jonathan Plasse
dc4d7619ee Add Diagnostic.try_amend() to simplify error handling (#3701) 2023-03-24 17:10:11 -04:00
Jonathan Plasse
1bac206995 Revert "Replace logical_lines feature with debug_assertions (#3648)" (#3708) 2023-03-23 23:42:56 -04:00
Jonathan Plasse
efc6e8cb39 Exempt PLR1711 and RET501 if non-None annotation (#3705) 2023-03-24 03:11:58 +00:00
Jonathan Plasse
7f3b748401 Fix Ruff pre-commit hook errors (#3706) 2023-03-23 22:52:24 -04:00
Jonathan Plasse
7da06b9741 Allow simple container literals as default values (#3703) 2023-03-23 22:51:36 -04:00
Charlie Marsh
0f95056f13 Avoid panics for implicitly concatenated forward references (#3700) 2023-03-23 19:13:50 -04:00
Charlie Marsh
028329854b Avoid parsing f-strings in type annotations (#3699) 2023-03-23 18:51:44 -04:00
Charlie Marsh
ba43d6bd0b Avoid parsing ForwardRef contents as type references (#3698) 2023-03-23 18:44:02 -04:00
Charlie Marsh
e8d17d23cb Expand the scope of useless-expression (B018) (#3455) 2023-03-23 18:33:58 -04:00
Jonathan Plasse
aea925a898 Fix SIM118 auto-fix (#3695) 2023-03-23 17:14:56 -04:00
Charlie Marsh
f58345dee3 Bump version to v0.0.259 (#3691) 2023-03-23 14:52:42 -04:00
Charlie Marsh
71c0da27bb Avoid nested loops in missing_whitespace (#3688) 2023-03-23 14:18:59 -04:00
Charlie Marsh
8a2d1a3029 Respect all rule-exemption sources when suppressing parser errors (#3665) 2023-03-23 13:36:48 -04:00
Micha Reiser
6161e56ea4 Fix RuleSet.remove (#3685) 2023-03-23 17:01:37 +00:00
Charlie Marsh
189c9d4683 Add dedicated structs for BindingKind variants (#3672) 2023-03-22 19:08:48 -04:00
Charlie Marsh
615887a7fe Bump version to v0.0.258 (#3671) 2023-03-22 15:02:57 -04:00
Charlie Marsh
07808a58f2 Refactor out common exemption-parsing logic (#3670) 2023-03-22 15:02:07 -04:00
Ran Benita
fe568c08d2 isort: fix bad interaction between force-sort-within-sections and force-to-top (#3645) 2023-03-22 14:00:00 -04:00
Charlie Marsh
7741d43ae5 Allow pairwise diagnostics for zip(..., strict=True) (#3669) 2023-03-22 13:03:43 -04:00
Charlie Marsh
1b3e54231c Flag, but don't fix, unused imports in ModuleNotFoundError blocks (#3658) 2023-03-22 13:03:30 -04:00
Charlie Marsh
3a8e98341b Enable autofix for annotations within 'simple' string literals (#3657) 2023-03-22 12:45:51 -04:00
kyoto7250
8593739f88 Check indentation level when executing E231 (#3668) 2023-03-22 12:32:00 -04:00
Charlie Marsh
242dd3dae1 Rename remaining use-* rules (#3661) 2023-03-22 11:36:01 -04:00
Charlie Marsh
875f61cb62 Rename pathlib rules to match updated naming convention (#3660) 2023-03-22 11:35:45 -04:00
Jonathan Plasse
3ec1ea8ac2 Add cargo-udeps in CI (#3646) 2023-03-22 15:53:12 +01:00
Charlie Marsh
1e45b13958 Remove linked issue from flake8-django (#3664) 2023-03-22 03:26:22 +00:00
Dhruv Manilawala
9e61956711 [flake8-django]: Implement rule DJ012 (#3659) 2023-03-22 03:07:58 +00:00
Jonathan Plasse
5eae3fbbfb Avoid RUF007 fixes for more than two arguments (#3654) 2023-03-21 22:17:31 +00:00
Colin Delahunty
41e38ffa98 [flake8-bandit]: Implement deny-list rules for suspicious member calls (#3239) 2023-03-21 15:11:52 -04:00
Charlie Marsh
27903cdb11 Replace logical_lines feature with debug_assertions (#3648) 2023-03-21 12:16:41 -04:00
Charlie Marsh
3b1709ba1e Avoid attempting infinite open fix with re-bound builtin (#3650) 2023-03-21 15:32:31 +00:00
Dhruv Manilawala
33394e4a69 docs: all flake8-comprehension rules (#3631) 2023-03-21 14:28:19 +00:00
Charlie Marsh
7b9bdc494a Consider same-site fixes to be overlapping (#3638) 2023-03-21 10:09:47 -04:00
James Greenhill
b06ca25421 Add PostHog to users of Ruff in README (#3641) 2023-03-21 10:05:35 -04:00
Jonathan Plasse
c42f8b93d2 Add Swatinem/rust-cache to benchmark-compare job (#3637) 2023-03-21 14:45:09 +01:00
Micha Reiser
f59a22b6e5 Remove unused dependencies (#3644) 2023-03-21 11:02:41 +01:00
Jonathan Plasse
b5edc6dfc9 Add autofix functionality for F523 (#3613) 2023-03-21 03:55:23 +00:00
Charlie Marsh
626169e2ef Avoid raising PEP 604 errors with forward-referenced members (#3640) 2023-03-20 23:49:41 -04:00
Charlie Marsh
e9f359ac5e Convert single-argument %-style format calls (#3600) 2023-03-21 03:35:10 +00:00
Jacob Latonis
318c2c80e2 pylint: Implement binary-op-exception (PLW0711) (#3639) 2023-03-21 03:33:40 +00:00
Jonathan Plasse
92aa3a8178 Use language: system for Rust hooks (#3616) 2023-03-20 22:44:21 -04:00
Jonathan Plasse
22a4ab51f9 Handle UP032 autofix with adjacent keywords (#3636) 2023-03-21 00:17:45 +00:00
Jonathan Plasse
f70a49ed8b Add autofix for magic methods (ANN204) (#3633) 2023-03-20 19:19:20 -04:00
Charlie Marsh
f039bf36a2 Avoid trimming escaped whitespace in D210 (#3635) 2023-03-20 17:17:42 -04:00
Jonathan Plasse
169dd72328 Fix TRY300 false positive (#3634) 2023-03-20 20:55:28 +00:00
Jonathan Plasse
fd39ec4bdd Merge Availability and AutofixKind (#3629) 2023-03-20 16:45:33 +00:00
Charlie Marsh
7c0f17279c Flag PEP 585 and PEP 604 violations in quoted annotations (#3593) 2023-03-20 11:15:44 -04:00
konstin
81d0884974 Add basic jupyter notebook support (#3440)
* Add basic jupyter notebook support behind a feature flag

* Address review comments

* Rename in separate commit to make both git and clippy happy

* cfg(feature = "jupyter_notebook") another test

* Address more review comments

* Address more review comments

* and clippy and windows

* More review comment
2023-03-20 12:06:01 +01:00
Jacob Latonis
a45753f462 [pylint]: Implement assert-on-string-literal (W0129) (#3610) 2023-03-19 23:45:51 -04:00
Zhengbo Wang
b08326162b Doc/CLN: pass pre-commit (#3604) 2023-03-19 19:20:11 +00:00
Dhruv Manilawala
3a65af4dae feat: update C416 with dict comprehension (autofixable) (#3605) 2023-03-19 18:37:28 +00:00
Ville Lindholm
474aa0b196 Fix infinite loop due to rules D207 & W605 (#3609) 2023-03-19 18:29:13 +00:00
Charlie Marsh
4892167217 Avoid panics for implicitly-concatenated docstrings (#3584)
## Summary

In the rare event that a docstring contains an implicit string concatenation, we currently have the potential to panic, because we assume that if a string starts with triple quotes, it _ends_ with triple quotes. But with implicit concatenation, that's not the case: a single `Expr` could start and end with different quote styles, because it can contain multiple string tokens.

Supporting these "properly" is pretty hard. In some cases it's hard to even know what the "right" behavior is. So for now, I'm just detecting and warning, which is better than a panic.

Closes #3543.

Closes #3585.
2023-03-19 14:16:50 -04:00
Micha Reiser
a5494b8541 Bitflag based RuleSet (#3606) 2023-03-19 17:09:06 +01:00
Micha Reiser
9ac9a1c69e Gracefully handle lint panics (#3509) 2023-03-19 17:08:38 +01:00
Rogdham
f06dff8af8 Change broken links in README to beta.ruff.rs (#3607) 2023-03-19 15:17:44 +00:00
Charlie Marsh
fe7443ce2f Use any_enabled in AST checker (#3601) 2023-03-19 10:44:33 -04:00
Henry Schreiner
4bdb2dd362 ci(check_ecosystem): add PyPa/build (#3569) 2023-03-18 19:09:22 -04:00
Henry Schreiner
53a4743631 ci: fix check_ecosystem (#3602) 2023-03-18 19:03:08 -04:00
Charlie Marsh
4ffcd8366a Rename a variety of rules to match updated conventions (#3283) 2023-03-18 17:35:59 -04:00
Charlie Marsh
dfb772c6f1 Avoid removing comment hash for noqa's with trailing content (#3589) 2023-03-18 18:48:52 +00:00
Jonathan Plasse
c21eb06922 Fix D417 false positive (#3596) 2023-03-18 13:14:03 -04:00
Charlie Marsh
16a350c731 Reduce usage of ALL in ecosystem CI (#3590) 2023-03-18 13:13:09 -04:00
Charlie Marsh
fa04861724 Check exclusions prior to resolving pyproject.toml files (#3588) 2023-03-18 13:12:49 -04:00
Micha Reiser
404504ab41 CI Checks: Fix malformed markdown (#3595)
The Benchmark results aren't formatted properly if the ecosystem check finds differences because the ecosystem check doesn't emit a trailing newline.

This PR adds the trailing newline to the ecosystem check script.
2023-03-18 10:04:50 +00:00
Charlie Marsh
621e4353e3 Re-add the list of supported plugins to the README (#3592) 2023-03-17 23:33:37 -04:00
Charlie Marsh
0c4926ff7b Bump version to v0.0.257 (#3591) 2023-03-17 22:34:10 -04:00
tomecki
61653b9f27 [pylint] Implement useless-return (R1711) (#3116) 2023-03-17 18:30:32 -04:00
Charlie Marsh
8dd3959e74 Update output in resources/test/project/README.md (#3587) 2023-03-17 21:51:03 +00:00
Charlie Marsh
50f9db21da Enable ANSI colors on Windows 10 (#3583) 2023-03-17 17:34:39 -04:00
Tomer Chachamu
1dd3cbd047 [pylint] invalid-characters-* (#3552) 2023-03-17 19:30:41 +00:00
Johan
bd935cbd49 [flake8-bugbear] Add no-explicit-stacklevel (B028) (#3550) 2023-03-17 19:20:08 +00:00
Charlie Marsh
babd0a05ac Avoid adding dashed line outside of docstring (#3581) 2023-03-17 14:40:32 -04:00
Micha Reiser
87fab4a2e1 Benchmark all rules (#3570) 2023-03-17 19:29:39 +01:00
Charlie Marsh
2e21920adf Respect type overrides in E721 (#3582) 2023-03-17 14:29:05 -04:00
Micha Reiser
dedf4cbdeb refactor: Move scope and binding types to scope.rs (#3573) 2023-03-17 17:31:33 +01:00
Micha Reiser
92179e6369 Scope and Binding IDs (#3572) 2023-03-17 17:12:27 +01:00
Evan Rittenhouse
33d2457909 Prefer itertools.pairwise() over zip() for successive pairs (RUF007) (#3501) 2023-03-16 23:50:45 -04:00
Charlie Marsh
373a77e8c2 Avoid C1901 violations within subscripts (#3517) 2023-03-17 02:52:05 +00:00
Jacob Latonis
73df267635 [pylint]: Implement continue-in-finally (E0116) (#3541) 2023-03-17 02:47:49 +00:00
Jonathan Plasse
f5e5caaa25 Fix autofix conflict between D209 and D400 (#3564) 2023-03-17 02:36:25 +00:00
Henry Schreiner
d9ed0aae69 ci(check_ecosystem): add cibuildwheel (#3567) 2023-03-16 22:34:56 -04:00
Charlie Marsh
e0df62b841 Rewrite mock import with starred imports (#3566) 2023-03-16 20:54:29 -04:00
Henry Schreiner
bbc87b7177 ci(check_ecosystem): add scikit-build-core (#3563) 2023-03-16 19:46:42 -04:00
Charlie Marsh
667130a4c3 Add some additional users to the users list (#3565) 2023-03-16 23:32:17 +00:00
Nyakku Shigure
72febf98b7 add PaddlePaddle to Who's Using Ruff? (#3562) 2023-03-16 14:20:11 -04:00
Xuehai Pan
e99e1fae2b ci: add python/typeshed to ecosystem check (#3559) 2023-03-16 14:19:48 -04:00
Micha Reiser
eff84442bc refactor: Add Copy implementation to Rule (#3556) 2023-03-16 17:50:18 +01:00
Micha Reiser
aa51ecedc5 ci: Benchmark CI Step (#3480) 2023-03-16 09:05:10 +01:00
Edgar R. M
9ae9cc9d2f Use value > max style in pylint and mccabe messages (#3553) 2023-03-16 01:37:25 -04:00
Micha Reiser
de1106b95a Allow dispatching the PR comment job for testing (#3535) 2023-03-15 09:34:53 +01:00
Charlie Marsh
e636c5fcf0 Avoid unused argument violations in .pyi files (#3533) 2023-03-15 03:17:19 +00:00
Charlie Marsh
12dfd57211 Bump version to v0.0.256 (#3531) 2023-03-14 22:52:21 -04:00
Charlie Marsh
d188d242a0 Avoid tracking as-imports separately with force-single-line (#3530) 2023-03-15 02:26:01 +00:00
Charlie Marsh
57796c5e59 Add last remaining deprecated typing imports (#3529) 2023-03-15 00:08:09 +00:00
Charlie Marsh
2545869797 Avoid PEP 604 isinstance errors for starred tuples (#3527) 2023-03-14 22:08:43 +00:00
Charlie Marsh
58353a4bf4 Avoid PEP 604 panic with empty tuple (#3526) 2023-03-14 22:02:15 +00:00
Charlie Marsh
a36139ae21 Replicate inline comments when splitting single-line imports (#3521) 2023-03-14 14:48:12 -04:00
Jonathan Plasse
7e904111b1 Fix PYI011 and add auto-fix (#3492) 2023-03-14 14:43:09 -04:00
Charlie Marsh
344daebb1b Refine complexity rules for try-except-else-finally (#3519) 2023-03-14 14:40:33 -04:00
Charlie Marsh
432059de35 Allow # ruff: prefix for isort action comments (#3493) 2023-03-14 14:34:28 -04:00
Charlie Marsh
c50d6da8b4 Allow string percent formatting in os.getenv (#3518) 2023-03-14 14:27:21 -04:00
Charlie Marsh
1b738f88c4 Allow f-strings and concatenations in os.getenv (#3516) 2023-03-14 17:46:34 +00:00
Charlie Marsh
1eff3dffa5 Ensure that redirect warnings appear exactly once per code (#3500) 2023-03-14 15:22:14 +00:00
Xuehai Pan
8c7317eb8d ci: fix missing short tag for cloudflare/wrangler-action (#3513) 2023-03-14 15:16:09 +00:00
Charlie Marsh
106a93eab0 Make Clap an optional feature for ruff crate (#3498) 2023-03-14 11:02:05 -04:00
Xuehai Pan
78c2b0ac47 ci: add dependabot integration for GitHub Actions (#3504) 2023-03-14 10:31:26 -04:00
Micha Reiser
d5700d7c69 Add Micro Benchmark (#3466) 2023-03-14 08:35:07 +01:00
Samuel Cormier-Iijima
3a7bdb39c9 Fix base ref determination for artifact download in ecosystem CI check (#3499) 2023-03-13 22:37:12 -04:00
Grzegorz Bokota
a82fe4a139 Fix lack of not in PLC1901 error message (#3497) 2023-03-13 19:19:41 -04:00
Charlie Marsh
62ff3b62e3 Add requires-python inference to docs (#3495) 2023-03-13 18:14:39 -04:00
Charlie Marsh
1e5db58b7b Include individual path checks in --verbose logging (#3489) 2023-03-13 17:13:47 -04:00
Charlie Marsh
a6e998d639 Remove Wasm-specific Rayon workarounds (#3490) 2023-03-13 16:48:43 -04:00
Charlie Marsh
a8c1915e2e Remove erroneous C4-to-C40 redirect (#3488) 2023-03-13 19:52:05 +00:00
Xuehai Pan
c515a1b31a PYI011: allow math constants in defaults (#3484) 2023-03-13 14:23:00 -04:00
Charlie Marsh
aa97a092bd Bump version to v0.0.255 (#3485) 2023-03-13 14:06:51 -04:00
Micha Reiser
685c242761 refactor(ruff_python_ast): Split get_argument (#3478) 2023-03-13 18:18:25 +01:00
Jonathan Plasse
b540407b74 Infer target-version from project metadata (#3470)
* Infer target-version from project metadata

* Fix requires-python with ">=3.8.16"

* Load requires-python at runtime

* Use upstream VersionSpecifiers

* Add debug information when parsing ruff.toml

* Display debug only if target_version is not set

* Bump pep440-rs to add impl Error for Pep440Error
2023-03-13 18:16:01 +01:00
Charlie Marsh
3a5fbd6d74 Upgrade RustPython to fix Serde dependency (#3481) 2023-03-13 12:29:31 -04:00
Charlie Marsh
227679b5cb Re-enable the T and C linter prefix selectors (#3452) 2023-03-13 08:20:30 -04:00
Charlie Marsh
c2750a59ab Implement an iterator for universal newlines (#3454)
# Summary

We need to support CR line endings (as opposed to LF and CRLF line endings, which are already supported). They're rare, but they do appear in Python code, and we tend to panic on any file that uses them.

Our `Locator` abstraction now supports CR line endings. However, Rust's `str#lines` implementation does _not_.

This PR adds a `UniversalNewlineIterator` implementation that respects all of CR, LF, and CRLF line endings, and plugs it into most of the `.lines()` call sites.

As an alternative design, it could be nice if we could leverage `Locator` for this. We've already computed all of the line endings, so we could probably iterate much more efficiently?

# Test Plan

Largely relying on automated testing, however, also ran over some known failure cases, like #3404.
2023-03-13 00:01:29 -04:00
Charlie Marsh
2a4d6ab3b2 Remove unnecessary Path::new from fs calls (#3476) 2023-03-12 23:18:23 -04:00
Charlie Marsh
7a80bcec58 Output GitLab paths relative to CI_PROJECT_DIR (#3475) 2023-03-13 03:03:37 +00:00
Y.D.X
297749a3a8 [doc] Update FAQ on Flake8 for structural pattern matching (#3473) 2023-03-13 02:27:22 +00:00
Charlie Marsh
8955e32b5c Respect ignores for runtime-import-in-type-checking-block (TCH004) (#3474) 2023-03-13 02:23:26 +00:00
Charlie Marsh
cd192eddf9 Add some new users to the README (#3471) 2023-03-13 00:08:58 +00:00
Jacob Latonis
675227db5c pylint: E1507 invalid-envvar-value (#3467) 2023-03-12 21:43:06 +00:00
Charlie Marsh
a65c6806a6 Avoid respecting noqa directives when RUF100 is enabled (#3469) 2023-03-12 14:37:35 -04:00
Calum Young
6c576872d4 List changes for all ecosystem repos (#3461) 2023-03-12 14:30:38 -04:00
Xuehai Pan
9858df1ac9 [FIX] PYI011: recognize Bool / Float / Complex numbers as simple defaults (#3459) 2023-03-12 17:34:09 +00:00
Charlie Marsh
7fb7268e8a Use a hash to fingerprint GitLab CI output (#3456) 2023-03-12 00:22:39 -05:00
Jacob Latonis
0f78f27713 pylint: W1508 invalid-envvar-default (#3449) 2023-03-11 16:44:42 -05:00
Charlie Marsh
12a6fc7041 Avoid removing un-aliased exceptions in OSError-aliased handlers (#3451) 2023-03-11 15:24:11 -05:00
Micha Reiser
d2988043af perf: Optimize UTF8/ASCII byte offset index (#3439) 2023-03-11 13:12:10 +01:00
Micha Reiser
cc8b13d3a7 refactor: Replace Vec in options metadata with static array (#3433) 2023-03-11 09:03:56 +00:00
Charlie Marsh
1e081cf9a6 Flag deprecated (but renamed) imports in UP035 (#3448) 2023-03-11 01:06:32 -05:00
Charlie Marsh
841bcf1cdd Remove unnecessary Serde derives (#3447) 2023-03-11 00:16:51 -05:00
Charlie Marsh
7062d1db16 Run ecosystem CI checks without --isolated (#3445) 2023-03-10 19:03:51 -05:00
Jonathan Plasse
8b561313aa Remove empty line after RUF100 auto-fix (#3414) 2023-03-10 22:57:13 +00:00
Samuel Cormier-Iijima
cfa2924664 Setup ecosystem CI (#3390)
This PR sets up an "ecosystem" check as an optional part of the CI step for pull requests. The primary piece of this is a new script in `scripts/check_ecosystem.py` which takes two ruff binaries as input and compares their outputs against a corpus of open-source code in parallel. I used ruff's `text` reporting format and stdlib's `difflib` (rather than JSON output and jsondiffs) to avoid adding another dependency. There is a new ecosystem-comment workflow to add a comment to the PR (see [this link](https://securitylab.github.com/research/github-actions-preventing-pwn-requests/) which explains why it needs to be done as a new workflow for security reasons).
2023-03-10 17:39:07 -05:00
Florian Best
a3aeec6377 docs(pycodestyle): document rules (#3407) 2023-03-10 22:36:38 +00:00
Micha Reiser
b983d5eb3f fix: method red not found in release builds (#3434) 2023-03-10 10:17:35 +01:00
kyoto7250
bb3bb24b59 Autofix PIE810 rule violations (#3411) 2023-03-10 05:17:22 +00:00
Charlie Marsh
872829ca72 When "Args" and "Parameters" are present, prefer NumPy style (#3430) 2023-03-10 02:58:05 +00:00
Charlie Marsh
2383228709 Respect --show-fixes with --fix-only (#3426) 2023-03-09 21:37:39 +00:00
Aryaman Marathe
952307d39d [pylint] C1901: compare-to-empty-string (#3405) 2023-03-09 21:33:34 +00:00
Charlie Marsh
024caca233 Introduce a ruff_diagnostics crate (#3409)
## Summary

This PR moves `Diagnostic`, `DiagnosticKind`, and `Fix` into their own crate, which will enable us to further split up Ruff, since sub-linter crates (which need to implement functions that return `Diagnostic`) can now depend on `ruff_diagnostics` rather than Ruff.
2023-03-09 20:48:57 +00:00
DanCardin
08ec11a31e fix: Emit a more useful error if an extend points at a non-existent ruff.toml file. (#3417) 2023-03-09 19:55:09 +00:00
Micha Reiser
bd05a8a74d fix: WASM tests (#3415) 2023-03-09 11:27:59 +01:00
Micha Reiser
229f1c34cb refactor: Extract ruff_wasm (#3401) 2023-03-09 10:07:39 +00:00
Charlie Marsh
a7f3532395 Ignore multiply-assigned variables in RET504 (#3393) 2023-03-08 19:11:55 -05:00
Aaron Cunningham
3349ceb969 [flake8-bugbear] Add flake8-bugbear's B030 rule (#3400) 2023-03-08 20:41:29 +00:00
Charlie Marsh
da1f83fe32 Remove core module from ruff_python_formatter (#3373) 2023-03-08 19:11:39 +00:00
Charlie Marsh
0a9d259f9c Remove copied core modules from ruff_python_formatter (#3371) 2023-03-08 19:03:40 +00:00
Charlie Marsh
130e733023 Implement From<Located> for Range (#3377) 2023-03-08 18:50:20 +00:00
Charlie Marsh
ff2c0dd491 Use shared leading_quote implementation in ruff_python_formatter (#3396) 2023-03-08 18:21:59 +00:00
Charlie Marsh
dfe1cad928 Rename DiagnosticKind#commit to DiagnosticKind#suggestion (#3397) 2023-03-08 18:06:19 +00:00
Charlie Marsh
ffad0bcdaa Decouple Diagnostic from "all violations" enumeration (#3352) 2023-03-08 17:51:37 +00:00
Jonathan Plasse
bc869d4f52 Fix PIE802 broken auto-fix with trailing comma (#3402) 2023-03-08 12:49:01 -05:00
Micha Reiser
a3de791f0a Make ruff_cli binary a small wrapper around lib (#3398) 2023-03-08 12:11:55 +01:00
Charlie Marsh
d9dfec30eb Catch RET504 usages via decorators (#3395) 2023-03-08 00:38:01 +00:00
Charlie Marsh
3f04def3a5 Remap ChainMap, Counter, and OrderedDict imports to collections (#3392) 2023-03-07 23:53:35 +00:00
Charlie Marsh
98177754de Handle multi-line fixes for byte-string prefixing (#3391) 2023-03-07 23:33:47 +00:00
Tom Forbes
8d5374762c Relax minimum rust version to allow for point releases (#3389) 2023-03-07 13:52:25 -05:00
Charlie Marsh
bad6bdda1f Create a rust_python_ast crate (#3370)
This PR productionizes @MichaReiser's suggestion in https://github.com/charliermarsh/ruff/issues/1820#issuecomment-1440204423, by creating a separate crate for the `ast` module (`rust_python_ast`). This will enable us to further split up the `ruff` crate, as we'll be able to create (e.g.) separate sub-linter crates that have access to these common AST utilities.

This was mostly a straightforward copy (with adjustments to module imports), as the few dependencies that _did_ require modifications were handled in #3366, #3367, and #3368.
2023-03-07 15:18:40 +00:00
Charlie Marsh
a5d302fcbf Pass Range struct by value (#3376) 2023-03-07 09:53:31 -05:00
Charlie Marsh
bced58ce40 Rename runtime-evaluated-baseclasses to runtime-evaluated-base-classes (#3379) 2023-03-07 09:51:12 -05:00
Aaron Cunningham
10e252e2fb Updated forced-separate type from Rust to abstract (#3380) 2023-03-07 09:35:39 -05:00
Sasan Jacob Rasti
4dead7541f Implement configuration options runtime-evaluated-decorators and runtime-evaluated-baseclasses for flake8-type-checking (#3292) 2023-03-06 23:34:19 -05:00
Charlie Marsh
fea1af5a63 Include entire prefix when reporting rule selector errors (#3375) 2023-03-07 00:04:52 +00:00
Charlie Marsh
c0ad875339 Remove unnecessary quote-stripping method (#3372) 2023-03-06 18:28:20 -05:00
Charlie Marsh
8437399496 Remove AST checker's dependency on resolver (#3368) 2023-03-06 21:45:09 +00:00
StefanBRas
074f5634a5 Remove duplicate info in azure format (#3369) 2023-03-06 16:40:03 -05:00
Charlie Marsh
694d41897a Move visibility module into ast crate (#3367) 2023-03-06 20:14:47 +00:00
Charlie Marsh
e1ebd9130d Don't enforce typing-import rules in .pyi files (#3362) 2023-03-06 15:03:34 -05:00
Charlie Marsh
fc8ca6edd2 Remove source_code's dependency on pydocstyle (#3366) 2023-03-06 15:01:01 -05:00
konstin
709dba2e71 Remove old define_violation! (in favor of #[violation]) (#3310) 2023-03-06 17:00:29 +00:00
Charlie Marsh
d1c48016eb Rename ruff_python crate to ruff_python_stdlib (#3354)
In hindsight, `ruff_python` is too general. A good giveaway is that it's actually a prefix of some other crates. The intent of this crate is to reimplement pieces of the Python standard library and CPython itself, so `ruff_python_stdlib` feels appropriate.
2023-03-06 13:43:22 +00:00
konstin
348a38d261 Deprecate define violation (#3358)
* Add `#[violation]` proc macro as a replacement for `define_violation!`

* Switch all rules to #[violation]
2023-03-06 10:59:06 +00:00
konstin
22e6778e17 Add cargo dev generate-all --check and catch outdated docs in cargo test (#3320) 2023-03-06 11:28:38 +01:00
StefanBRas
30c71dc59a Add Azure Devops as a -format option. (#3335) 2023-03-06 02:48:39 +00:00
Charlie Marsh
5d8591fec4 Skip byte-order-mark at start of file (#3343) 2023-03-05 21:37:14 -05:00
Carlos Gonçalves
673aa6e90f feat(e231): add rule + autofix (#3344) 2023-03-05 20:09:35 +00:00
Charlie Marsh
51fe9f7d4b Treat unary operations on constants as constant-like (#3348) 2023-03-04 16:30:33 -05:00
Charlie Marsh
d7767b2bad Use u8 to represent ambiguous representants (#3345) 2023-03-04 16:01:05 -05:00
Charlie Marsh
40d3b40c14 Move binding and scope tracking into a separate ast::Context struct (#3298) 2023-03-04 14:01:20 -05:00
Charlie Marsh
376ef929b1 Upgrade RustPython (#3341) 2023-03-04 14:01:03 -05:00
Jonathan Plasse
8828e12283 Bump dependencies and move more shared dependencies into workspace (#3340) 2023-03-04 12:36:26 -05:00
Charlie Marsh
f13633cc9f Avoid panicking in invalid_escape_sequence (#3338) 2023-03-04 12:14:33 -05:00
Evan Rittenhouse
889c05c87e Explicitly put Path(...) in Pathlib violations (#3333) 2023-03-04 04:33:12 +00:00
Charlie Marsh
bbbc44336e Bump version to 0.0.254 (#3331) 2023-03-03 19:11:07 -05:00
Charlie Marsh
d216b2aaa8 Treat callables within type definitions as default-non-types (#3329) 2023-03-03 23:07:30 +00:00
Charlie Marsh
367cc43c42 Un-gate PEP 604 isinstance rewrites from keep_runtime_typing checks (#3328) 2023-03-03 17:29:41 -05:00
Charlie Marsh
b5b26d5a3e Gate PEP604 isinstance rewrites behind Python 3.10+ (#3327) 2023-03-03 22:22:14 +00:00
Charlie Marsh
dedf8aa5cc Use presence of convention-specific sections during docstring inference (#3325) 2023-03-03 17:13:11 -05:00
Charlie Marsh
eb42ce9319 Extend RET503 autofixes to "end of statement", including comments (#3324) 2023-03-03 19:15:55 +00:00
Micha Reiser
cdbe2ee496 refactor: Introduce CacheKey trait (#3323)
This PR introduces a new `CacheKey` trait for types that can be used as a cache key.

I'm not entirely sure if this is worth the "overhead", but I was surprised to find `HashableHashSet` and got scared when I looked at the time complexity of the `hash` function. These implementations must be extremely slow in hashed collections.

I then searched for usages and quickly realized that only the cache uses these `Hash` implementations, where performance is less sensitive.

This PR introduces a new `CacheKey` trait to communicate the difference between a hash and computing a key for the cache. The new trait can be implemented for types that don't implement `Hash` for performance reasons, and we can define additional constraints on the implementation:  For example, we'll want to enforce portability when we add remote caching support. Using a different trait further allows us not to implement it for types without stable identities (e.g. pointers) or use other implementations than the standard hash function.
2023-03-03 18:29:49 +00:00
konstin
d1288dc2b1 Remove maturin build from CI (#3322)
maturin build generally works when cargo build works, so imho it's not worth running it with every CI run.
2023-03-03 16:50:26 +01:00
konstin
3bcffb5bdd Add flake-pyi PYI033 "Do not use type comments in stubs" (#3302) 2023-03-03 10:45:34 -05:00
Martin Packman
98209be8aa Detect quote style ignoring docstrings (#3306)
Currently the quote style of the first string in a file is used for autodetecting what to use when rewriting code for fixes. This is an okay heuristic, but often the first line in a file is a docstring, rather than a string constant, and it's not uncommon for pre-Black code to have different quoting styles for those.

For example, in the Google style guide:
https://google.github.io/styleguide/pyguide.html
> Be consistent with your choice of string quote character within a file. Pick ' or " and stick with it. ... Docstrings must use """ regardless.

This branch adjusts the logic to instead skip over any `"""` triple doublequote string tokens. The default, if there are no single quoted strings, is still to use double quote as the style.
2023-03-02 23:59:33 -05:00
Charlie Marsh
a03fa93c3a Abort when unable to fix relative imports past module root (#3319) 2023-03-03 04:38:51 +00:00
Charlie Marsh
4de3882088 Upgrade RustPython (#3316) 2023-03-02 22:59:29 -05:00
Charlie Marsh
3a98b68dc0 Always include @classmethod and @staticmethod in decorator lists (#3314) 2023-03-03 03:49:04 +00:00
Carlos Gonçalves
7e291e542d feat(e225,226,227,228): add rules (#3300) 2023-03-02 22:54:45 +00:00
Carlos Gonçalves
6f649d6579 feat(E211): add rule + autofix (#3313) 2023-03-02 22:48:04 +00:00
Yaroslav Chvanov
508bc605a5 Implement property-decorators configuration option for pydocstyle (#3311) 2023-03-02 16:59:56 -05:00
Charlie Marsh
ffdf6e35e6 Treat function type annotations within classes as runtime-required (#3312) 2023-03-02 16:45:26 -05:00
Martin Lehoux
886992c6c2 Replace tuples with type union in isinstance or issubclass calls (#3280) 2023-03-02 15:59:15 -05:00
2744 changed files with 193211 additions and 107781 deletions

View File

@@ -1,5 +1,6 @@
[alias]
dev = "run --package ruff_dev --bin ruff_dev"
benchmark = "bench -p ruff_benchmark --bench linter --bench formatter --"
[target.'cfg(all())']
rustflags = [
@@ -25,4 +26,12 @@ rustflags = [
"-Wclippy::print_stdout",
"-Wclippy::print_stderr",
"-Wclippy::dbg_macro",
"-Wclippy::empty_drop",
"-Wclippy::empty_structs_with_brackets",
"-Wclippy::exit",
"-Wclippy::get_unwrap",
"-Wclippy::rc_buffer",
"-Wclippy::rc_mutex",
"-Wclippy::rest_pat_in_fully_bound_structs",
"-Wunreachable_pub"
]

View File

@@ -0,0 +1,46 @@
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
// README at: https://github.com/devcontainers/templates/tree/main/src/rust
{
"name": "Ruff",
"image": "mcr.microsoft.com/devcontainers/rust:0-1-bullseye",
"mounts": [
{
"source": "devcontainer-cargo-cache-${devcontainerId}",
"target": "/usr/local/cargo",
"type": "volume"
}
],
"customizations": {
"codespaces": {
"openFiles": [
"CONTRIBUTING.md"
]
},
"vscode": {
"extensions": [
"ms-python.python",
"rust-lang.rust-analyzer",
"serayuzgur.crates",
"tamasfe.even-better-toml",
"Swellaby.vscode-rust-test-adapter",
"charliermarsh.ruff"
],
"settings": {
"rust-analyzer.updates.askBeforeDownload": false
}
}
},
// Features to add to the dev container. More info: https://containers.dev/features.
"features": {
"ghcr.io/devcontainers/features/python": {
"installTools": false
}
},
// Use 'forwardPorts' to make a list of ports inside the container available locally.
// "forwardPorts": [],
"postCreateCommand": ".devcontainer/post-create.sh"
// Configure tool-specific properties.
// "customizations": {},
// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
// "remoteUser": "root"
}

8
.devcontainer/post-create.sh Executable file
View File

@@ -0,0 +1,8 @@
#!/usr/bin/env bash
rustup default < rust-toolchain
rustup component add clippy rustfmt
cargo install cargo-insta
cargo fetch
pip install maturin pre-commit

View File

@@ -12,3 +12,9 @@ indent_size = 2
[*.{rs,py}]
indent_size = 4
[*.snap]
trim_trailing_whitespace = false
[*.md]
max_line_length = 100

9
.github/CODEOWNERS vendored Normal file
View File

@@ -0,0 +1,9 @@
# GitHub code owners file. For more info: https://help.github.com/articles/about-codeowners/
#
# - Comment lines begin with `#` character.
# - Each line is a file pattern followed by one or more owners.
# - The '*' pattern is global owners.
# - Order is important. The last matching pattern has the most precedence.
# Jupyter
/crates/ruff/src/jupyter/ @dhruvmanila

15
.github/PULL_REQUEST_TEMPLATE.md vendored Normal file
View File

@@ -0,0 +1,15 @@
<!--
Thank you for contributing to Ruff! To help us out with reviewing, please consider the following:
- Does this pull request include a summary of the change? (See below.)
- Does this pull request include a descriptive title?
- Does this pull request include references to any relevant issues?
-->
## Summary
<!-- What's the purpose of the change? What does it do, and why? -->
## Test Plan
<!-- How was it tested? -->

11
.github/dependabot.yml vendored Normal file
View File

@@ -0,0 +1,11 @@
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
day: "monday"
time: "12:00"
timezone: "America/New_York"
commit-message:
prefix: "ci(deps)"

5
.github/release.yml vendored
View File

@@ -1,5 +1,9 @@
# https://docs.github.com/en/repositories/releasing-projects-on-github/automatically-generated-release-notes#configuring-automatically-generated-release-notes
changelog:
exclude:
labels:
- internal
- documentation
categories:
- title: Breaking Changes
labels:
@@ -11,6 +15,7 @@ changelog:
- title: Settings
labels:
- configuration
- cli
- title: Bug Fixes
labels:
- bug

128
.github/workflows/benchmark.yaml vendored Normal file
View File

@@ -0,0 +1,128 @@
name: Benchmark
on:
pull_request:
workflow_dispatch:
concurrency:
group: ${{ github.workflow }}-${{ github.ref_name }}-${{ github.event.pull_request.number || github.sha }}
cancel-in-progress: true
jobs:
run-benchmark:
if: github.event_name == 'pull_request'
name: "Run | ${{ matrix.os }}"
strategy:
matrix:
os: [ ubuntu-latest, windows-latest ]
runs-on: ${{ matrix.os }}
steps:
- name: "PR - Checkout Branch"
uses: actions/checkout@v3
with:
ref: ${{ github.event.pull_request.head.sha }}
- name: "PR - Install Rust toolchain"
run: rustup show
- uses: Swatinem/rust-cache@v2
- name: "PR - Build benchmarks"
run: cargo bench -p ruff_benchmark --no-run
- name: "PR - Run benchmarks"
run: cargo benchmark --save-baseline=pr
- name: "Main - Checkout Branch"
uses: actions/checkout@v3
with:
clean: false
ref: main
- name: "Main - Install Rust toolchain"
run: rustup show
- name: "Main - Build benchmarks"
run: cargo bench -p ruff_benchmark --no-run
- name: "Main - Run benchmarks"
run: cargo benchmark --save-baseline=main
- name: "Upload benchmark results"
uses: actions/upload-artifact@v3
with:
name: benchmark-results-${{ matrix.os }}
path: ./target/criterion
# Cleanup
- name: Remove Criterion Artifact
uses: JesseTG/rm@v1.0.3
with:
path: ./target/criterion
benchmark-compare:
if: github.event_name == 'pull_request'
runs-on: ubuntu-latest
name: Compare
needs:
- run-benchmark
steps:
- name: "Install Rust toolchain"
run: rustup show
- name: "Install critcmp"
uses: taiki-e/install-action@v2
with:
tool: critcmp
- name: "Linux | Download PR benchmark results"
uses: actions/download-artifact@v3
with:
name: benchmark-results-ubuntu-latest
path: ./target/criterion
- name: "Linux | Compare benchmark results"
shell: bash
run: |
echo "### Benchmark" >> summary.md
echo "#### Linux" >> summary.md
echo "\`\`\`" >> summary.md
critcmp main pr >> summary.md
echo "\`\`\`" >> summary.md
echo "" >> summary.md
- name: "Linux | Cleanup benchmark results"
run: rm -rf ./target/criterion
- name: "Windows | Download PR benchmark results"
uses: actions/download-artifact@v3
with:
name: benchmark-results-windows-latest
path: ./target/criterion
- name: "Windows | Compare benchmark results"
shell: bash
run: |
echo "#### Windows" >> summary.md
echo "\`\`\`" >> summary.md
critcmp main pr >> summary.md
echo "\`\`\`" >> summary.md
echo "" >> summary.md
echo ${{ github.event.pull_request.number }} > pr-number
cat summary.md > $GITHUB_STEP_SUMMARY
- uses: actions/upload-artifact@v3
name: Upload PR Number
with:
name: pr-number
path: pr-number
- uses: actions/upload-artifact@v3
name: Upload Summary
with:
name: summary
path: summary.md

View File

@@ -2,7 +2,7 @@ name: CI
on:
push:
branches: [main]
branches: [ main ]
pull_request:
workflow_dispatch:
@@ -15,22 +15,10 @@ env:
CARGO_NET_RETRY: 10
CARGO_TERM_COLOR: always
RUSTUP_MAX_RETRIES: 10
PACKAGE_NAME: ruff
PYTHON_VERSION: "3.7" # to build abi3 wheels
jobs:
cargo-build:
name: "cargo build"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: "Install Rust toolchain"
run: rustup show
- uses: Swatinem/rust-cache@v1
- run: cargo build --all
- run: ./target/debug/ruff_dev generate-all
- run: git diff --quiet README.md || echo "::error file=README.md::This file is outdated. Run 'cargo dev generate-all'."
- run: git diff --quiet ruff.schema.json || echo "::error file=ruff.schema.json::This file is outdated. Run 'cargo dev generate-all'."
- run: git diff --exit-code -- README.md ruff.schema.json docs
cargo-fmt:
name: "cargo fmt"
runs-on: ubuntu-latest
@@ -48,7 +36,7 @@ jobs:
- name: "Install Rust toolchain"
run: |
rustup component add clippy
- uses: Swatinem/rust-cache@v1
- uses: Swatinem/rust-cache@v2
- run: cargo clippy --workspace --all-targets --all-features -- -D warnings
cargo-clippy-wasm:
@@ -60,22 +48,22 @@ jobs:
run: |
rustup component add clippy
rustup target add wasm32-unknown-unknown
- uses: Swatinem/rust-cache@v1
- run: cargo clippy -p ruff --target wasm32-unknown-unknown --all-features -- -D warnings
- uses: Swatinem/rust-cache@v2
- run: cargo clippy -p ruff_wasm --target wasm32-unknown-unknown --all-features -- -D warnings
cargo-test:
strategy:
matrix:
os: [ubuntu-latest, windows-latest]
os: [ ubuntu-latest, windows-latest ]
runs-on: ${{ matrix.os }}
name: "cargo test | ${{ matrix.os }}"
steps:
- uses: actions/checkout@v3
- name: "Install Rust toolchain"
run: rustup show
- uses: Swatinem/rust-cache@v1
- uses: Swatinem/rust-cache@v2
- run: cargo install cargo-insta
- run: pip install black[d]==22.12.0
- run: pip install black[d]==23.1.0
- name: "Run tests (Ubuntu)"
if: ${{ matrix.os == 'ubuntu-latest' }}
run: |
@@ -88,11 +76,54 @@ jobs:
cargo insta test --all --all-features
git diff --exit-code
- run: cargo test --package ruff_cli --test black_compatibility_test -- --ignored
# Skipped as it's currently broken. The resource were moved from the
# ruff_cli to ruff crate, but this test was not updated.
if: false
# Check for broken links in the documentation.
- run: cargo doc --all --no-deps
env:
# Setting RUSTDOCFLAGS because `cargo doc --check` isn't yet implemented (https://github.com/rust-lang/cargo/issues/10025).
RUSTDOCFLAGS: "-D warnings"
- uses: actions/upload-artifact@v3
if: ${{ matrix.os == 'ubuntu-latest' }}
with:
name: ruff
path: target/debug/ruff
cargo-fuzz:
runs-on: ubuntu-latest
name: "cargo fuzz"
steps:
- uses: actions/checkout@v3
- name: "Install Rust toolchain"
run: rustup show
- uses: Swatinem/rust-cache@v2
with:
workspaces: "fuzz -> target"
- name: "Install cargo-fuzz"
uses: taiki-e/install-action@v2
with:
tool: cargo-fuzz@0.11
- run: cargo fuzz build -s none
cargo-test-wasm:
runs-on: ubuntu-latest
name: "cargo test (wasm)"
steps:
- uses: actions/checkout@v3
- name: "Install Rust toolchain"
run: rustup target add wasm32-unknown-unknown
- uses: actions/setup-node@v3
with:
node-version: 18
cache: "npm"
cache-dependency-path: playground/package-lock.json
- uses: jetli/wasm-pack-action@v0.4.0
- uses: Swatinem/rust-cache@v2
- name: "Run wasm-pack"
run: |
cd crates/ruff_wasm
wasm-pack test --node
scripts:
name: "test scripts"
@@ -100,35 +131,148 @@ jobs:
steps:
- uses: actions/checkout@v3
- name: "Install Rust toolchain"
run: rustup show
- uses: Swatinem/rust-cache@v1
- run: ./scripts/add_rule.py --name DoTheThing --code PLC999 --linter pylint
run: rustup component add rustfmt
- uses: Swatinem/rust-cache@v2
- run: ./scripts/add_rule.py --name DoTheThing --prefix PL --code C0999 --linter pylint
- run: cargo check
- run: cargo fmt --all --check
- run: |
./scripts/add_plugin.py test --url https://pypi.org/project/-test/0.1.0/ --prefix TST
./scripts/add_rule.py --name FirstRule --code TST001 --linter test
./scripts/add_rule.py --name FirstRule --prefix TST --code 001 --linter test
- run: cargo check
- run: cargo fmt --all --check
maturin-build:
name: "maturin build"
ecosystem:
name: "ecosystem"
runs-on: ubuntu-latest
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'
steps:
- uses: actions/checkout@v3
- name: "Install Rust toolchain"
run: rustup show
- uses: Swatinem/rust-cache@v1
- uses: actions/setup-python@v4
with:
python-version: "3.11"
- run: pip install maturin
- run: maturin build -b bin
- run: python scripts/transform_readme.py --target pypi
typos:
name: "spell check"
- uses: actions/download-artifact@v3
name: Download Ruff binary
id: ruff-target
with:
name: ruff
path: target/debug
- uses: dawidd6/action-download-artifact@v2
name: Download base results
with:
name: ruff
branch: ${{ github.event.pull_request.base.ref }}
check_artifacts: true
- name: Run ecosystem check
run: |
# Make executable, since artifact download doesn't preserve this
chmod +x ruff ${{ steps.ruff-target.outputs.download-path }}/ruff
scripts/check_ecosystem.py ruff ${{ steps.ruff-target.outputs.download-path }}/ruff | tee ecosystem-result
cat ecosystem-result > $GITHUB_STEP_SUMMARY
echo ${{ github.event.number }} > pr-number
- uses: actions/upload-artifact@v3
name: Upload PR Number
with:
name: pr-number
path: pr-number
- uses: actions/upload-artifact@v3
name: Upload Results
with:
name: ecosystem-result
path: ecosystem-result
cargo-udeps:
name: "cargo udeps"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: crate-ci/typos@master
- name: "Install nightly Rust toolchain"
# Only pinned to make caching work, update freely
run: rustup toolchain install nightly-2023-06-08
- uses: Swatinem/rust-cache@v2
- name: "Install cargo-udeps"
uses: taiki-e/install-action@cargo-udeps
- name: "Run cargo-udeps"
run: cargo +nightly-2023-06-08 udeps
python-package:
name: "python package"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
with:
files: .
python-version: ${{ env.PYTHON_VERSION }}
architecture: x64
- uses: Swatinem/rust-cache@v2
- name: "Prep README.md"
run: python scripts/transform_readme.py --target pypi
- name: "Build wheels"
uses: PyO3/maturin-action@v1
with:
args: --out dist
- name: "Test wheel"
run: |
pip install --force-reinstall --find-links dist ${{ env.PACKAGE_NAME }}
ruff --help
python -m ruff --help
- name: "Remove wheels from cache"
run: rm -rf target/wheels
pre-commit:
name: "pre-commit"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
with:
python-version: "3.11"
- name: "Install Rust toolchain"
run: rustup show
- uses: Swatinem/rust-cache@v2
- name: "Install pre-commit"
run: pip install pre-commit
- name: "Cache pre-commit"
uses: actions/cache@v3
with:
path: ~/.cache/pre-commit
key: pre-commit-${{ hashFiles('.pre-commit-config.yaml') }}
- name: "Run pre-commit"
run: |
echo '```console' > $GITHUB_STEP_SUMMARY
# Enable color output for pre-commit and remove it for the summary
SKIP=cargo-fmt,clippy,dev-generate-all pre-commit run --all-files --show-diff-on-failure --color=always | \
tee >(sed -E 's/\x1B\[([0-9]{1,2}(;[0-9]{1,2})*)?[mGK]//g' >> $GITHUB_STEP_SUMMARY) >&1
exit_code=${PIPESTATUS[0]}
echo '```' >> $GITHUB_STEP_SUMMARY
exit $exit_code
docs:
name: "mkdocs"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
- name: "Install Rust toolchain"
run: rustup show
- uses: Swatinem/rust-cache@v2
- name: "Install dependencies"
run: pip install -r docs/requirements.txt
- name: "Update README File"
run: python scripts/transform_readme.py --target mkdocs
- name: "Generate docs"
run: python scripts/generate_mkdocs.py
- name: "Check docs formatting"
run: python scripts/check_docs_formatted.py
- name: "Build docs"
run: mkdocs build --strict

View File

@@ -1,9 +1,9 @@
name: mkdocs
on:
release:
types: [published]
workflow_dispatch:
release:
types: [ published ]
jobs:
mkdocs:
@@ -15,7 +15,7 @@ jobs:
- uses: actions/setup-python@v4
- name: "Install Rust toolchain"
run: rustup show
- uses: Swatinem/rust-cache@v1
- uses: Swatinem/rust-cache@v2
- name: "Install dependencies"
run: |
pip install -r docs/requirements.txt

View File

@@ -52,7 +52,7 @@ jobs:
- name: "Build wheels - universal2"
uses: PyO3/maturin-action@v1
with:
args: --release --universal2 --out dist -m ./${{ env.CRATE_NAME }}/Cargo.toml
args: --release --target universal2-apple-darwin --out dist -m ./${{ env.CRATE_NAME }}/Cargo.toml
- name: "Install built wheel - universal2"
run: |
pip install dist/${{ env.CRATE_NAME }}-*universal2.whl --force-reinstall
@@ -66,7 +66,7 @@ jobs:
runs-on: windows-latest
strategy:
matrix:
target: [x64, x86]
target: [ x64, x86 ]
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
@@ -94,7 +94,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
target: [x86_64, i686]
target: [ x86_64, i686 ]
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
@@ -121,7 +121,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
target: [aarch64, armv7, s390x, ppc64le, ppc64]
target: [ aarch64, armv7, s390x, ppc64le, ppc64 ]
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
@@ -133,7 +133,7 @@ jobs:
target: ${{ matrix.target }}
manylinux: auto
args: --no-default-features --release --out dist -m ./${{ env.CRATE_NAME }}/Cargo.toml
- uses: uraimo/run-on-arch-action@v2.5.0
- uses: uraimo/run-on-arch-action@v2
if: matrix.target != 'ppc64'
name: Install built wheel
with:
@@ -206,7 +206,7 @@ jobs:
target: ${{ matrix.platform.target }}
manylinux: musllinux_1_2
args: --release --out dist -m ./${{ env.CRATE_NAME }}/Cargo.toml
- uses: uraimo/run-on-arch-action@master
- uses: uraimo/run-on-arch-action@v2
name: Install built wheel
with:
arch: ${{ matrix.platform.arch }}

View File

@@ -2,8 +2,8 @@ name: "[Playground] Release"
on:
workflow_dispatch:
push:
branches: [main]
release:
types: [ published ]
env:
CARGO_INCREMENTAL: 0
@@ -28,7 +28,7 @@ jobs:
- uses: jetli/wasm-pack-action@v0.4.0
- uses: jetli/wasm-bindgen-action@v0.2.0
- name: "Run wasm-pack"
run: wasm-pack build --target web --out-dir ../../playground/src/pkg crates/ruff
run: wasm-pack build --target web --out-dir ../../playground/src/pkg crates/ruff_wasm
- name: "Install Node dependencies"
run: npm ci
working-directory: playground

84
.github/workflows/pr-comment.yaml vendored Normal file
View File

@@ -0,0 +1,84 @@
name: PR Check Comment
on:
workflow_run:
workflows: [ CI, Benchmark ]
types: [ completed ]
workflow_dispatch:
inputs:
workflow_run_id:
description: The ecosystem workflow that triggers the workflow run
required: true
permissions:
pull-requests: write
jobs:
comment:
runs-on: ubuntu-latest
steps:
- uses: dawidd6/action-download-artifact@v2
name: Download PR Number
with:
name: pr-number
run_id: ${{ github.event.workflow_run.id || github.event.inputs.workflow_run_id }}
if_no_artifact_found: ignore
- name: Extract PR Number
id: pr-number
run: |
if [[ -f pr-number ]]
then
echo "pr-number=$(<pr-number)" >> $GITHUB_OUTPUT
fi
- uses: dawidd6/action-download-artifact@v2
name: "Download Ecosystem Result"
id: download-ecosystem-result
if: steps.pr-number.outputs.pr-number
with:
name: ecosystem-result
workflow: ci.yaml
pr: ${{ steps.pr-number.outputs.pr-number }}
path: pr/ecosystem
if_no_artifact_found: ignore
- uses: dawidd6/action-download-artifact@v2
name: "Download Benchmark Result"
id: download-benchmark-result
if: steps.pr-number.outputs.pr-number
with:
name: summary
workflow: benchmark.yaml
pr: ${{ steps.pr-number.outputs.pr-number }}
path: pr/benchmark
if_no_artifact_found: ignore
- name: Generate Comment
id: generate-comment
if: steps.download-ecosystem-result.outputs.found_artifact == 'true' || steps.download-benchmark-result.outputs.found_artifact == 'true'
run: |
echo 'comment<<EOF' >> $GITHUB_OUTPUT
echo '## PR Check Results' >> $GITHUB_OUTPUT
if [[ -f pr/ecosystem/ecosystem-result ]]
then
echo "### Ecosystem" >> $GITHUB_OUTPUT
cat pr/ecosystem/ecosystem-result >> $GITHUB_OUTPUT
echo "" >> $GITHUB_OUTPUT
fi
if [[ -f pr/benchmark/summary.md ]]
then
cat pr/benchmark/summary.md >> $GITHUB_OUTPUT
fi
echo 'EOF' >> $GITHUB_OUTPUT
- name: Create or update comment
if: steps.generate-comment.outputs.comment
uses: thollander/actions-comment-pull-request@v2
with:
pr_number: ${{ steps.pr-number.outputs.pr-number }}
message: ${{ steps.generate-comment.outputs.comment }}
comment_tag: PR Check Results

View File

@@ -2,8 +2,17 @@ name: "[ruff] Release"
on:
workflow_dispatch:
release:
types: [published]
inputs:
tag:
description: "The version to tag, without the leading 'v'. If omitted, will initiate a dry run skipping uploading artifact."
type: string
sha:
description: "Optionally, the full sha of the commit to be released"
type: string
push:
paths:
# When we change pyproject.toml, we want to ensure that the maturin builds still work
- pyproject.toml
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
@@ -18,6 +27,32 @@ env:
RUSTUP_MAX_RETRIES: 10
jobs:
sdist:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
with:
python-version: ${{ env.PYTHON_VERSION }}
- name: "Prep README.md"
run: python scripts/transform_readme.py --target pypi
- name: "Build sdist"
uses: PyO3/maturin-action@v1
with:
command: sdist
args: --out dist
- name: "Test sdist"
run: |
rustup default $(cat rust-toolchain)
pip install dist/${{ env.PACKAGE_NAME }}-*.tar.gz --force-reinstall
ruff --help
python -m ruff --help
- name: "Upload sdist"
uses: actions/upload-artifact@v3
with:
name: wheels
path: dist
macos-x86_64:
runs-on: macos-latest
steps:
@@ -32,10 +67,12 @@ jobs:
uses: PyO3/maturin-action@v1
with:
target: x86_64
args: --release --out dist --sdist
- name: "Install built wheel - x86_64"
args: --release --out dist
- name: "Test wheel - x86_64"
run: |
pip install dist/${{ env.PACKAGE_NAME }}-*.whl --force-reinstall
ruff --help
python -m ruff --help
- name: "Upload wheels"
uses: actions/upload-artifact@v3
with:
@@ -43,9 +80,9 @@ jobs:
path: dist
- name: "Archive binary"
run: |
ARCHIVE_FILE=ruff-x86_64-apple-darwin.tar.gz
tar czvf $ARCHIVE_FILE -C target/x86_64-apple-darwin/release ruff
shasum -a 256 $ARCHIVE_FILE > $ARCHIVE_FILE.sha256
ARCHIVE_FILE=ruff-x86_64-apple-darwin.tar.gz
tar czvf $ARCHIVE_FILE -C target/x86_64-apple-darwin/release ruff
shasum -a 256 $ARCHIVE_FILE > $ARCHIVE_FILE.sha256
- name: "Upload binary"
uses: actions/upload-artifact@v3
with:
@@ -67,10 +104,12 @@ jobs:
- name: "Build wheels - universal2"
uses: PyO3/maturin-action@v1
with:
args: --release --universal2 --out dist
- name: "Install built wheel - universal2"
args: --release --target universal2-apple-darwin --out dist
- name: "Test wheel - universal2"
run: |
pip install dist/${{ env.PACKAGE_NAME }}-*universal2.whl --force-reinstall
ruff --help
python -m ruff --help
- name: "Upload wheels"
uses: actions/upload-artifact@v3
with:
@@ -78,9 +117,9 @@ jobs:
path: dist
- name: "Archive binary"
run: |
ARCHIVE_FILE=ruff-aarch64-apple-darwin.tar.gz
tar czvf $ARCHIVE_FILE -C target/aarch64-apple-darwin/release ruff
shasum -a 256 $ARCHIVE_FILE > $ARCHIVE_FILE.sha256
ARCHIVE_FILE=ruff-aarch64-apple-darwin.tar.gz
tar czvf $ARCHIVE_FILE -C target/aarch64-apple-darwin/release ruff
shasum -a 256 $ARCHIVE_FILE > $ARCHIVE_FILE.sha256
- name: "Upload binary"
uses: actions/upload-artifact@v3
with:
@@ -113,11 +152,13 @@ jobs:
with:
target: ${{ matrix.platform.target }}
args: --release --out dist
- name: "Install built wheel"
- name: "Test wheel"
if: ${{ !startsWith(matrix.platform.target, 'aarch64') }}
shell: bash
run: |
python -m pip install dist/${{ env.PACKAGE_NAME }}-*.whl --force-reinstall
ruff --help
python -m ruff --help
- name: "Upload wheels"
uses: actions/upload-artifact@v3
with:
@@ -126,9 +167,9 @@ jobs:
- name: "Archive binary"
shell: bash
run: |
ARCHIVE_FILE=ruff-${{ matrix.platform.target }}.zip
7z a $ARCHIVE_FILE ./target/${{ matrix.platform.target }}/release/ruff.exe
sha256sum $ARCHIVE_FILE > $ARCHIVE_FILE.sha256
ARCHIVE_FILE=ruff-${{ matrix.platform.target }}.zip
7z a $ARCHIVE_FILE ./target/${{ matrix.platform.target }}/release/ruff.exe
sha256sum $ARCHIVE_FILE > $ARCHIVE_FILE.sha256
- name: "Upload binary"
uses: actions/upload-artifact@v3
with:
@@ -158,10 +199,12 @@ jobs:
target: ${{ matrix.target }}
manylinux: auto
args: --release --out dist
- name: "Install built wheel"
- name: "Test wheel"
if: ${{ startsWith(matrix.target, 'x86_64') }}
run: |
pip install dist/${{ env.PACKAGE_NAME }}-*.whl --force-reinstall
ruff --help
python -m ruff --help
- name: "Upload wheels"
uses: actions/upload-artifact@v3
with:
@@ -169,9 +212,9 @@ jobs:
path: dist
- name: "Archive binary"
run: |
ARCHIVE_FILE=ruff-${{ matrix.target }}.tar.gz
tar czvf $ARCHIVE_FILE -C target/${{ matrix.target }}/release ruff
shasum -a 256 $ARCHIVE_FILE > $ARCHIVE_FILE.sha256
ARCHIVE_FILE=ruff-${{ matrix.target }}.tar.gz
tar czvf $ARCHIVE_FILE -C target/${{ matrix.target }}/release ruff
shasum -a 256 $ARCHIVE_FILE > $ARCHIVE_FILE.sha256
- name: "Upload binary"
uses: actions/upload-artifact@v3
with:
@@ -187,6 +230,9 @@ jobs:
platform:
- target: aarch64-unknown-linux-gnu
arch: aarch64
# see https://github.com/astral-sh/ruff/issues/3791
# and https://github.com/gnzlbg/jemallocator/issues/170#issuecomment-1503228963
maturin_docker_options: -e JEMALLOC_SYS_WITH_LG_PAGE=16
- target: armv7-unknown-linux-gnueabihf
arch: armv7
- target: s390x-unknown-linux-gnu
@@ -195,6 +241,7 @@ jobs:
arch: ppc64le
- target: powerpc64-unknown-linux-gnu
arch: ppc64
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
@@ -207,10 +254,11 @@ jobs:
with:
target: ${{ matrix.platform.target }}
manylinux: auto
docker-options: ${{ matrix.platform.maturin_docker_options }}
args: --release --out dist
- uses: uraimo/run-on-arch-action@v2.5.0
- uses: uraimo/run-on-arch-action@v2
if: matrix.platform.arch != 'ppc64'
name: Install built wheel
name: Test wheel
with:
arch: ${{ matrix.platform.arch }}
distro: ubuntu20.04
@@ -221,6 +269,7 @@ jobs:
pip3 install -U pip
run: |
pip3 install ${{ env.PACKAGE_NAME }} --no-index --find-links dist/ --force-reinstall
ruff --help
- name: "Upload wheels"
uses: actions/upload-artifact@v3
with:
@@ -228,9 +277,9 @@ jobs:
path: dist
- name: "Archive binary"
run: |
ARCHIVE_FILE=ruff-${{ matrix.platform.target }}.tar.gz
tar czvf $ARCHIVE_FILE -C target/${{ matrix.platform.target }}/release ruff
shasum -a 256 $ARCHIVE_FILE > $ARCHIVE_FILE.sha256
ARCHIVE_FILE=ruff-${{ matrix.platform.target }}.tar.gz
tar czvf $ARCHIVE_FILE -C target/${{ matrix.platform.target }}/release ruff
shasum -a 256 $ARCHIVE_FILE > $ARCHIVE_FILE.sha256
- name: "Upload binary"
uses: actions/upload-artifact@v3
with:
@@ -260,7 +309,7 @@ jobs:
target: ${{ matrix.target }}
manylinux: musllinux_1_2
args: --release --out dist
- name: "Install built wheel"
- name: "Test wheel"
if: matrix.target == 'x86_64-unknown-linux-musl'
uses: addnab/docker-run-action@v3
with:
@@ -269,6 +318,8 @@ jobs:
run: |
apk add py3-pip
pip3 install ${{ env.PACKAGE_NAME }} --no-index --find-links /io/dist/ --force-reinstall
ruff --help
python -m ruff --help
- name: "Upload wheels"
uses: actions/upload-artifact@v3
with:
@@ -276,9 +327,9 @@ jobs:
path: dist
- name: "Archive binary"
run: |
ARCHIVE_FILE=ruff-${{ matrix.target }}.tar.gz
tar czvf $ARCHIVE_FILE -C target/${{ matrix.target }}/release ruff
shasum -a 256 $ARCHIVE_FILE > $ARCHIVE_FILE.sha256
ARCHIVE_FILE=ruff-${{ matrix.target }}.tar.gz
tar czvf $ARCHIVE_FILE -C target/${{ matrix.target }}/release ruff
shasum -a 256 $ARCHIVE_FILE > $ARCHIVE_FILE.sha256
- name: "Upload binary"
uses: actions/upload-artifact@v3
with:
@@ -294,8 +345,10 @@ jobs:
platform:
- target: aarch64-unknown-linux-musl
arch: aarch64
maturin_docker_options: -e JEMALLOC_SYS_WITH_LG_PAGE=16
- target: armv7-unknown-linux-musleabihf
arch: armv7
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
@@ -309,8 +362,9 @@ jobs:
target: ${{ matrix.platform.target }}
manylinux: musllinux_1_2
args: --release --out dist
- uses: uraimo/run-on-arch-action@master
name: Install built wheel
docker-options: ${{ matrix.platform.maturin_docker_options }}
- uses: uraimo/run-on-arch-action@v2
name: Test wheel
with:
arch: ${{ matrix.platform.arch }}
distro: alpine_latest
@@ -319,6 +373,7 @@ jobs:
apk add py3-pip
run: |
pip3 install ${{ env.PACKAGE_NAME }} --no-index --find-links dist/ --force-reinstall
ruff check --help
- name: "Upload wheels"
uses: actions/upload-artifact@v3
with:
@@ -326,9 +381,9 @@ jobs:
path: dist
- name: "Archive binary"
run: |
ARCHIVE_FILE=ruff-${{ matrix.platform.target }}.tar.gz
tar czvf $ARCHIVE_FILE -C target/${{ matrix.platform.target }}/release ruff
shasum -a 256 $ARCHIVE_FILE > $ARCHIVE_FILE.sha256
ARCHIVE_FILE=ruff-${{ matrix.platform.target }}.tar.gz
tar czvf $ARCHIVE_FILE -C target/${{ matrix.platform.target }}/release ruff
shasum -a 256 $ARCHIVE_FILE > $ARCHIVE_FILE.sha256
- name: "Upload binary"
uses: actions/upload-artifact@v3
with:
@@ -348,27 +403,83 @@ jobs:
- linux-cross
- musllinux
- musllinux-cross
if: "startsWith(github.ref, 'refs/tags/')"
# If you don't set an input it's a dry run skipping uploading artifact
if: ${{ inputs.tag }}
environment:
name: release
permissions:
# For pypi trusted publishing
id-token: write
# For GitHub release publishing
contents: write
steps:
- name: Consistency check tag
run: |
version=$(grep "version = " pyproject.toml | sed -e 's/version = "\(.*\)"/\1/g')
if [ "${{ inputs.tag }}" != "${version}" ]; then
echo "The input tag does not match the version from pyproject.toml:" >&2
echo "${{ inputs.tag }}" >&2
echo "${version}" >&2
exit 1
else
echo "Releasing ${version}"
fi
- name: Consistency check sha
if: ${{ inputs.sha }}
run: |
git_sha=$(git rev-parse HEAD)
if [ "${{ inputs.sha }}" != "${git_sha}" ]; then
echo "The specified sha does not match the git checkout" >&2
echo "${{ inputs.sha }}" >&2
echo "${git_sha}" >&2
exit 1
else
echo "Releasing ${git_sha}"
fi
- uses: actions/download-artifact@v3
with:
name: wheels
- uses: actions/setup-python@v4
- name: "Publish to PyPi"
env:
TWINE_USERNAME: __token__
TWINE_PASSWORD: ${{ secrets.RUFF_TOKEN }}
run: |
pip install --upgrade twine
twine upload --skip-existing *
- name: "Update pre-commit mirror"
run: |
curl -X POST -H "Accept: application/vnd.github+json" -H "Authorization: Bearer ${{ secrets.RUFF_PRE_COMMIT_PAT }}" -H "X-GitHub-Api-Version: 2022-11-28" https://api.github.com/repos/charliermarsh/ruff-pre-commit/dispatches --data '{"event_type": "pypi_release"}'
path: wheels
- name: Publish to PyPi
uses: pypa/gh-action-pypi-publish@release/v1
with:
skip-existing: true
packages-dir: wheels
verbose: true
- uses: actions/download-artifact@v3
with:
name: binaries
path: binaries
- name: Release
- name: git tag
run: |
git config user.email "hey@astral.sh"
git config user.name "Ruff Release CI"
git tag -m "v${{ inputs.tag }}" "v${{ inputs.tag }}"
# If there is duplicate tag, this will fail. The publish to pypi action will have been a noop (due to skip
# existing), so we make a non-destructive exit here
git push --tags
- name: "Publish to GitHub"
uses: softprops/action-gh-release@v1
with:
draft: true
files: binaries/*
tag_name: v${{ inputs.tag }}
# After the release has been published, we update downstream repositories
# This is separate because if this fails the release is still fine, we just need to do some manual workflow triggers
update-dependents:
name: Release
runs-on: ubuntu-latest
needs: release
steps:
- name: "Update pre-commit mirror"
uses: actions/github-script@v6
with:
github-token: ${{ secrets.RUFF_PRE_COMMIT_PAT }}
script: |
github.rest.actions.createWorkflowDispatch({
owner: 'astral-sh',
repo: 'ruff-pre-commit',
workflow_id: 'main.yml',
ref: 'main',
})

22
.gitignore vendored
View File

@@ -1,8 +1,26 @@
# Local cache
.ruff_cache
# Benchmarking cpython (CONTRIBUTING.md)
crates/ruff/resources/test/cpython
# generate_mkdocs.py
mkdocs.yml
.overrides
# check_ecosystem.py
ruff-old
github_search*.jsonl
# update_schemastore.py
schemastore
# `maturin develop` and ecosystem_all_check.sh
.venv*
# Formatter debugging (crates/ruff_python_formatter/README.md)
scratch.py
# Created by `perf` (CONTRIBUTING.md)
perf.data
perf.data.old
# Created by `flamegraph` (CONTRIBUTING.md)
flamegraph.svg
# Additional target directories that don't invalidate the main compile cache when changing linker settings,
# e.g. `CARGO_TARGET_DIR=target-maturin maturin build --release --strip` or
# `CARGO_TARGET_DIR=target-llvm-lines RUSTFLAGS="-Csymbol-mangling-version=v0" cargo llvm-lines -p ruff --lib`
/target*
###
# Rust.gitignore

14
.markdownlint.yaml Normal file
View File

@@ -0,0 +1,14 @@
# default to true for all rules
default: true
# MD033/no-inline-html
MD033: false
# MD041/first-line-h1
MD041: false
# MD013/line-length
MD013:
line_length: 100
code_blocks: false
ignore_code_blocks: true

View File

@@ -1,7 +1,17 @@
fail_fast: true
exclude: |
(?x)^(
crates/ruff/resources/.*|
crates/ruff/src/rules/.*/snapshots/.*|
crates/ruff_cli/resources/.*|
crates/ruff_python_formatter/resources/.*|
crates/ruff_python_formatter/src/snapshots/.*
)$
repos:
- repo: https://github.com/abravalheri/validate-pyproject
rev: v0.10.1
rev: v0.12.1
hooks:
- id: validate-pyproject
@@ -17,52 +27,37 @@ repos:
rev: v0.33.0
hooks:
- id: markdownlint-fix
args:
- --disable
- MD013 # line-length
- MD033 # no-inline-html
- --
- repo: https://github.com/crate-ci/typos
rev: v1.14.12
hooks:
- id: typos
- repo: local
hooks:
- id: cargo-fmt
name: cargo fmt
entry: cargo fmt --
language: rust
types: [rust]
- id: clippy
name: clippy
entry: cargo clippy --workspace --all-targets --all-features -- -D warnings
language: rust
pass_filenames: false
language: system
types: [ rust ]
pass_filenames: false # This makes it a lot faster
- id: ruff
name: ruff
entry: cargo run -p ruff_cli -- check --no-cache --force-exclude --fix --exit-non-zero-on-fix
language: rust
types_or: [python, pyi]
entry: cargo run --bin ruff -- check --no-cache --force-exclude --fix --exit-non-zero-on-fix
language: system
types_or: [ python, pyi ]
require_serial: true
exclude: |
(?x)^(
crates/ruff/resources/.*|
crates/ruff_python_formatter/resources/.*
)$
- id: dev-generate-all
name: dev-generate-all
entry: cargo dev generate-all
language: rust
pass_filenames: false
exclude: target
# Black
- repo: https://github.com/psf/black
rev: 23.1.0
hooks:
- id: black
exclude: |
(?x)^(
crates/ruff/resources/.*|
crates/ruff_python_formatter/resources/.*
)$
ci:
skip: [cargo-fmt, clippy, dev-generate-all]
skip: [ cargo-fmt, dev-generate-all ]

View File

@@ -1,15 +1,81 @@
# Breaking Changes
## 0.0.268
### The `keep-runtime-typing` setting has been removed ([#4427](https://github.com/astral-sh/ruff/pull/4427))
Enabling the `keep-runtime-typing` option, located under the `pyupgrade` section, is equivalent
to ignoring the `UP006` and `UP007` rules via Ruff's standard `ignore` mechanism. As there's no
need for a dedicated setting to disable these rules, the `keep-runtime-typing` option has been
removed.
## 0.0.267
### `update-check` is no longer a valid configuration option ([#4313](https://github.com/astral-sh/ruff/pull/4313))
The `update-check` functionality was deprecated in [#2530](https://github.com/astral-sh/ruff/pull/2530),
in that the behavior itself was removed, and Ruff was changed to warn when that option was enabled.
Now, Ruff will throw an error when `update-check` is provided via a configuration file (e.g.,
`update-check = false`) or through the command-line, since it has no effect. Users should remove
this option from their configuration.
## 0.0.265
### `--fix-only` now exits with a zero exit code, unless `--exit-non-zero-on-fix` is specified ([#4146](https://github.com/astral-sh/ruff/pull/4146))
Previously, `--fix-only` would exit with a non-zero exit code if any fixes were applied. This
behavior was inconsistent with `--fix`, and further, meant that `--exit-non-zero-on-fix` was
effectively ignored when `--fix-only` was specified.
Now, `--fix-only` will exit with a zero exit code, unless `--exit-non-zero-on-fix` is specified,
in which case it will exit with a non-zero exit code if any fixes were applied.
## 0.0.260
### Fixes are now represented as a list of edits ([#3709](https://github.com/astral-sh/ruff/pull/3709))
Previously, Ruff represented each fix as a single edit, which prohibited Ruff from automatically
fixing violations that required multiple edits across a file. As such, Ruff now represents each
fix as a list of edits.
This primarily affects the JSON API. Ruff's JSON representation used to represent the `fix` field as
a single edit, like so:
```json
{
"message": "Remove unused import: `sys`",
"content": "",
"location": {"row": 1, "column": 0},
"end_location": {"row": 2, "column": 0}
}
```
The updated representation instead includes a list of edits:
```json
{
"message": "Remove unused import: `sys`",
"edits": [
{
"content": "",
"location": {"row": 1, "column": 0},
"end_location": {"row": 2, "column": 0},
}
]
}
```
## 0.0.246
### `multiple-statements-on-one-line-def` (`E704`) was removed ([#2773](https://github.com/charliermarsh/ruff/pull/2773))
### `multiple-statements-on-one-line-def` (`E704`) was removed ([#2773](https://github.com/astral-sh/ruff/pull/2773))
This rule was introduced in v0.0.245. However, it turns out that pycodestyle and Flake8 ignore this
rule by default, as it is not part of PEP 8. As such, we've removed it from Ruff.
## 0.0.245
### Ruff's public `check` method was removed ([#2709](https://github.com/charliermarsh/ruff/pull/2709))
### Ruff's public `check` method was removed ([#2709](https://github.com/astral-sh/ruff/pull/2709))
Previously, Ruff exposed a `check` method as a public Rust API. This method was used by few,
if any clients, and was not well documented or supported. As such, it has been removed, with
@@ -17,10 +83,11 @@ the intention of adding a stable public API in the future.
## 0.0.238
### `select`, `extend-select`, `ignore`, and `extend-ignore` have new semantics ([#2312](https://github.com/charliermarsh/ruff/pull/2312))
### `select`, `extend-select`, `ignore`, and `extend-ignore` have new semantics ([#2312](https://github.com/astral-sh/ruff/pull/2312))
Previously, the interplay between `select` and its related options could lead to unexpected
behavior. For example, `ruff --select E501 --ignore ALL` and `ruff --select E501 --extend-ignore ALL` behaved differently. (See [#2312](https://github.com/charliermarsh/ruff/pull/2312) for more
behavior. For example, `ruff --select E501 --ignore ALL` and `ruff --select E501 --extend-ignore ALL`
behaved differently. (See [#2312](https://github.com/astral-sh/ruff/pull/2312) for more
examples.)
When Ruff determines the enabled rule set, it has to reconcile `select` and `ignore` from a variety
@@ -46,14 +113,14 @@ ignore = ["F401"]
Running `ruff --select F` would previously have enabled all `F` rules, apart from `F401`. Now, it
will enable all `F` rules, including `F401`, as the command line's `--select` resets the resolution.
### `remove-six-compat` (`UP016`) has been removed ([#2332](https://github.com/charliermarsh/ruff/pull/2332))
### `remove-six-compat` (`UP016`) has been removed ([#2332](https://github.com/astral-sh/ruff/pull/2332))
The `remove-six-compat` rule has been removed. This rule was only useful for one-time Python 2-to-3
upgrades.
## 0.0.237
### `--explain`, `--clean`, and `--generate-shell-completion` are now subcommands ([#2190](https://github.com/charliermarsh/ruff/pull/2190))
### `--explain`, `--clean`, and `--generate-shell-completion` are now subcommands ([#2190](https://github.com/astral-sh/ruff/pull/2190))
`--explain`, `--clean`, and `--generate-shell-completion` are now implemented as subcommands:
@@ -96,14 +163,14 @@ no change in behavior. However, please note the following exceptions:
## 0.0.226
### `misplaced-comparison-constant` (`PLC2201`) was deprecated in favor of `SIM300` ([#1980](https://github.com/charliermarsh/ruff/pull/1980))
### `misplaced-comparison-constant` (`PLC2201`) was deprecated in favor of `SIM300` ([#1980](https://github.com/astral-sh/ruff/pull/1980))
These two rules contain (nearly) identical logic. To deduplicate the rule set, we've upgraded
`SIM300` to handle a few more cases, and deprecated `PLC2201` in favor of `SIM300`.
## 0.0.225
### `@functools.cache` rewrites have been moved to a standalone rule (`UP033`) ([#1938](https://github.com/charliermarsh/ruff/pull/1938))
### `@functools.cache` rewrites have been moved to a standalone rule (`UP033`) ([#1938](https://github.com/astral-sh/ruff/pull/1938))
Previously, `UP011` handled both `@functools.lru_cache()`-to-`@functools.lru_cache` conversions,
_and_ `@functools.lru_cache(maxsize=None)`-to-`@functools.cache` conversions. The latter has been
@@ -112,7 +179,7 @@ to reflect the change in rule code.
## 0.0.222
### `--max-complexity` has been removed from the CLI ([#1877](https://github.com/charliermarsh/ruff/pull/1877))
### `--max-complexity` has been removed from the CLI ([#1877](https://github.com/astral-sh/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.
@@ -127,7 +194,7 @@ max-complexity = 10
## 0.0.181
### Files excluded by `.gitignore` are now ignored ([#1234](https://github.com/charliermarsh/ruff/pull/1234))
### Files excluded by `.gitignore` are now ignored ([#1234](https://github.com/astral-sh/ruff/pull/1234))
Ruff will now avoid checking files that are excluded by `.ignore`, `.gitignore`,
`.git/info/exclude`, and global `gitignore` files. This behavior is powered by the [`ignore`](https://docs.rs/ignore/latest/ignore/struct.WalkBuilder.html#ignore-rules)
@@ -140,9 +207,9 @@ default.
## 0.0.178
### Configuration files are now resolved hierarchically ([#1190](https://github.com/charliermarsh/ruff/pull/1190))
### Configuration files are now resolved hierarchically ([#1190](https://github.com/astral-sh/ruff/pull/1190))
`pyproject.toml` files are now resolved hierarchically, such that for each Python file, we find
the first `pyproject.toml` file in its path, and use that to determine its lint settings.
See the [README](https://github.com/charliermarsh/ruff#pyprojecttoml-discovery) for more.
See the [documentation](https://beta.ruff.rs/docs/configuration/#python-file-discovery) for more.

View File

@@ -8,6 +8,7 @@ Welcome! We're happy to have you here. Thank you in advance for your contributio
- [Project Structure](#project-structure)
- [Example: Adding a new lint rule](#example-adding-a-new-lint-rule)
- [Rule naming convention](#rule-naming-convention)
- [Rule testing: fixtures and snapshots](#rule-testing-fixtures-and-snapshots)
- [Example: Adding a new configuration option](#example-adding-a-new-configuration-option)
- [MkDocs](#mkdocs)
- [Release Process](#release-process)
@@ -20,18 +21,18 @@ Ruff welcomes contributions in the form of Pull Requests.
For small changes (e.g., bug fixes), feel free to submit a PR.
For larger changes (e.g., new lint rules, new functionality, new configuration options), consider
creating an [**issue**](https://github.com/charliermarsh/ruff/issues) outlining your proposed
change. You can also join us on [**Discord**](https://discord.gg/c9MhzV8aU5) to discuss your idea with
the community.
creating an [**issue**](https://github.com/astral-sh/ruff/issues) outlining your proposed change.
You can also join us on [**Discord**](https://discord.gg/c9MhzV8aU5) to discuss your idea with the
community.
If you're looking for a place to start, we recommend implementing a new lint rule (see:
[_Adding a new lint rule_](#example-adding-a-new-lint-rule), which will allow you to learn from and
pattern-match against the examples in the existing codebase. Many lint rules are inspired by
existing Python plugins, which can be used as a reference implementation.
As a concrete example: consider taking on one of the rules from the [`flake8-pyi`](https://github.com/charliermarsh/ruff/issues/848)
plugin, and looking to the originating [Python source](https://github.com/PyCQA/flake8-pyi)
for guidance.
As a concrete example: consider taking on one of the rules from the [`flake8-pyi`](https://github.com/astral-sh/ruff/issues/848)
plugin, and looking to the originating [Python source](https://github.com/PyCQA/flake8-pyi) for
guidance.
### Prerequisites
@@ -44,6 +45,12 @@ You'll also need [Insta](https://insta.rs/docs/) to update snapshot tests:
cargo install cargo-insta
```
and pre-commit to run some validation checks:
```shell
pipx install pre-commit # or `pip install pre-commit` if you have a virtualenv
```
### Development
After cloning the repository, run Ruff locally with:
@@ -56,9 +63,9 @@ Prior to opening a pull request, ensure that your code has been auto-formatted,
and that it passes both the lint and test validation checks:
```shell
cargo fmt # Auto-formatting...
cargo clippy --fix --workspace --all-targets --all-features # Linting...
cargo test # Testing...
cargo clippy --workspace --all-targets --all-features -- -D warnings # Rust linting
RUFF_UPDATE_SCHEMA=1 cargo test # Rust testing and updating ruff.schema.json
pre-commit run --all-files --show-diff-on-failure # Rust and Python formatting, Markdown and Python linting, etc.
```
These checks will run on GitHub Actions when you open your Pull Request, but running them locally
@@ -71,13 +78,6 @@ after running `cargo test` like so:
cargo insta review
```
If you have `pre-commit` [installed](https://pre-commit.com/#installation) then you can use it to
assist with formatting and linting. The following command will run the `pre-commit` hooks:
```shell
pre-commit run --all-files
```
Your Pull Request will be reviewed by a maintainer, which may involve a few rounds of iteration
prior to merging.
@@ -92,69 +92,123 @@ The vast majority of the code, including all lint rules, lives in the `ruff` cra
At time of writing, the repository includes the following crates:
- `crates/ruff`: library crate containing all lint rules and the core logic for running them.
- `crates/ruff_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`).
- `crates/ruff_dev`: binary crate containing utilities used in the development of Ruff itself (e.g.,
`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`: library crate containing macros used by Ruff.
- `crates/ruff_python`: library crate implementing Python-specific functionality (e.g., lists of standard library modules by versionb).
- `crates/flake8_to_ruff`: binary crate for generating Ruff configuration from Flake8 configuration.
- `crates/ruff_python_ast`: library crate containing Python-specific AST types and utilities.
- `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.
- `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
At a high level, the steps involved in adding a new lint rule are as follows:
1. Determine a name for the new rule as per our [rule naming convention](#rule-naming-convention).
1. Create a file for your rule (e.g., `crates/ruff/src/rules/flake8_bugbear/rules/abstract_base_class.rs`).
1. In that file, define a violation struct. You can grep for `define_violation!` to see examples.
1. Map the violation struct to a rule code in `crates/ruff/src/registry.rs` (e.g., `E402`).
1. Define the logic for triggering the violation in `crates/ruff/src/checkers/ast.rs` (for AST-based
checks), `crates/ruff/src/checkers/tokens.rs` (for token-based checks), `crates/ruff/src/checkers/lines.rs`
(for text-based checks), or `crates/ruff/src/checkers/filesystem.rs` (for filesystem-based
checks).
1. Add a test fixture.
1. Determine a name for the new rule as per our [rule naming convention](#rule-naming-convention)
(e.g., `AssertFalse`, as in, "allow `assert False`").
1. Create a file for your rule (e.g., `crates/ruff/src/rules/flake8_bugbear/rules/assert_false.rs`).
1. In that file, define a violation struct (e.g., `pub struct AssertFalse`). You can grep for
`#[violation]` to see examples.
1. In that file, define a function that adds the violation to the diagnostic list as appropriate
(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 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`).
1. Add proper [testing](#rule-testing-fixtures-and-snapshots) for your rule.
1. Update the generated files (documentation and generated code).
To define the violation, start by creating a dedicated file for your rule under the appropriate
rule linter (e.g., `crates/ruff/src/rules/flake8_bugbear/rules/abstract_base_class.rs`). That file should
contain a struct defined via `define_violation!`, along with a function that creates the violation
based on any required inputs. (Many of the existing examples live in `crates/ruff/src/violations.rs`,
but we're looking to place new rules in their own files.)
To trigger the violation, you'll likely want to augment the logic in `crates/ruff/src/checkers/ast.rs`,
which defines the Python AST visitor, responsible for iterating over the abstract syntax tree and
collecting diagnostics as it goes.
To trigger the violation, you'll likely want to augment the logic in `crates/ruff/src/checkers/ast.rs`
to call your new function at the appropriate time and with the appropriate inputs. The `Checker`
defined therein is a Python AST visitor, which iterates over the AST, building up a semantic model,
and calling out to lint rule analyzer functions as it goes.
If you need to inspect the AST, you can run `cargo dev print-ast` with a Python file. Grep
for the `Check::new` invocations to understand how other, similar rules are implemented.
for the `Diagnostic::new` invocations to understand how other, similar rules are implemented.
To add a test fixture, create a file under `crates/ruff/resources/test/fixtures/[linter]`, named to match
the code you defined earlier (e.g., `crates/ruff/resources/test/fixtures/pycodestyle/E402.py`). This file should
contain a variety of violations and non-violations designed to evaluate and demonstrate the behavior
of your lint rule.
Once you're satisfied with your code, add tests for your rule. See [rule testing](#rule-testing-fixtures-and-snapshots)
for more details.
Run `cargo dev generate-all` to generate the code for your new fixture. Then run Ruff
locally with (e.g.) `cargo run -p ruff_cli -- check crates/ruff/resources/test/fixtures/pycodestyle/E402.py --no-cache --select E402`.
Once you're satisfied with the output, codify the behavior as a snapshot test by adding a new
`test_case` macro in the relevant `crates/ruff/src/[linter]/mod.rs` file. Then, run `cargo test`.
Your test will fail, but you'll be prompted to follow-up with `cargo insta review`. Accept the
generated snapshot, then commit the snapshot file alongside the rest of your changes.
Finally, regenerate the documentation and generated code with `cargo dev generate-all`.
Finally, regenerate the documentation and other generated assets (like our JSON Schema) with:
`cargo dev generate-all`.
#### Rule naming convention
The rule name should make sense when read as "allow _rule-name_" or "allow _rule-name_ items".
Like Clippy, Ruff's rule names should make grammatical and logical sense when read as "allow
${rule}" or "allow ${rule} items", as in the context of suppression comments.
This implies that rule names:
For example, `AssertFalse` fits this convention: it flags `assert False` statements, and so a
suppression comment would be framed as "allow `assert False`".
- should state the bad thing being checked for
As such, rule names should...
- should not contain instructions on what you what you should use instead
(these belong in the rule documentation and the `autofix_title` for rules that have autofix)
- Highlight the pattern that is being linted against, rather than the preferred alternative.
For example, `AssertFalse` guards against `assert False` statements.
When re-implementing rules from other linters, this convention is given more importance than
- _Not_ contain instructions on how to fix the violation, which instead belong in the rule
documentation and the `autofix_title`.
- _Not_ contain a redundant prefix, like `Disallow` or `Banned`, which are already implied by the
convention.
When re-implementing rules from other linters, we prioritize adhering to this convention over
preserving the original rule name.
#### Rule testing: fixtures and snapshots
To test rules, Ruff uses snapshots of Ruff's output for a given file (fixture). Generally, there
will be one file per rule (e.g., `E402.py`), and each file will contain all necessary examples of
both violations and non-violations. `cargo insta review` will generate a snapshot file containing
Ruff's output for each fixture, which you can then commit alongside your changes.
Once you've completed the code for the rule itself, you can define tests with the following steps:
1. Add a Python file to `crates/ruff/resources/test/fixtures/[linter]` that contains the code you
want to test. The file name should match the rule name (e.g., `E402.py`), and it should include
examples of both violations and non-violations.
1. Run Ruff locally against your file and verify the output is as expected. Once you're satisfied
with the output (you see the violations you expect, and no others), proceed to the next step.
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
```
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,
e.g., `crates/ruff/src/rules/flake8_bugbear/mod.rs`)
1. Run `cargo test`. Your test will fail, but you'll be prompted to follow-up
with `cargo insta review`. Run `cargo insta review`, review and accept the generated snapshot,
then commit the snapshot file alongside the rest of your changes.
1. Run `cargo test` again to ensure that your test passes.
### Example: Adding a new configuration option
Ruff's user-facing settings live in a few different places.
@@ -185,6 +239,8 @@ Finally, regenerate the documentation and generated code with `cargo dev generat
To preview any changes to the documentation locally:
1. Install the [Rust toolchain](https://www.rust-lang.org/tools/install).
1. Install MkDocs and Material for MkDocs with:
```shell
@@ -215,6 +271,42 @@ them to [PyPI](https://pypi.org/project/ruff/).
Ruff follows the [semver](https://semver.org/) versioning standard. However, as pre-1.0 software,
even patch releases may contain [non-backwards-compatible changes](https://semver.org/#spec-item-4).
### Creating a new release
1. Update the version with `rg 0.0.269 --files-with-matches | xargs sed -i 's/0.0.269/0.0.270/g'`
1. Update `BREAKING_CHANGES.md`
1. Create a PR with the version and `BREAKING_CHANGES.md` updated
1. Merge the PR
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 havent tagged or
uploaded anything, you can restart after pushing a fix
1. Upload to pypi
1. Create and push the git tag (from pyproject.toml). We create the git tag only here
because we can't change it ([#4468](https://github.com/charliermarsh/ruff/issues/4468)), so
we want to make sure everything up to and including publishing to pypi worked.
1. Attach artifacts to draft GitHub release
1. Trigger downstream repositories. This can fail without causing fallout, it is possible (if
inconvenient) to trigger the downstream jobs manually
1. Create release notes in GitHub UI and promote from draft to proper release(<https://github.com/charliermarsh/ruff/releases/new>)
1. If needed, [update the schemastore](https://github.com/charliermarsh/ruff/blob/main/scripts/update_schemastore.py)
1. If needed, update ruff-lsp and ruff-vscode
## Ecosystem CI
GitHub Actions will run your changes against a number of real-world projects from GitHub and
report on any diagnostic differences. You can also run those checks locally via:
```shell
python scripts/check_ecosystem.py path/to/your/ruff path/to/older/ruff
```
You can also run the Ecosystem CI check in a Docker container across a larger set of projects by
downloading the [`known-github-tomls.json`](https://github.com/akx/ruff-usage-aggregate/blob/master/data/known-github-tomls.jsonl)
as `github_search.jsonl` and following the instructions in [scripts/Dockerfile.ecosystem](https://github.com/astral-sh/ruff/blob/main/scripts/Dockerfile.ecosystem).
Note that this check will take a while to run.
## Benchmarks
First, clone [CPython](https://github.com/python/cpython). It's a large and diverse Python codebase,

1836
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,33 +1,68 @@
[workspace]
members = ["crates/*"]
resolver = "2"
[workspace.package]
edition = "2021"
rust-version = "1.67.0"
rust-version = "1.70"
homepage = "https://beta.ruff.rs/docs"
documentation = "https://beta.ruff.rs/docs"
repository = "https://github.com/astral-sh/ruff"
authors = ["Charlie Marsh <charlie.r.marsh@gmail.com>"]
license = "MIT"
[workspace.dependencies]
anyhow = { version = "1.0.66" }
clap = { version = "4.0.1", features = ["derive"] }
itertools = { version = "0.10.5" }
anyhow = { version = "1.0.69" }
bitflags = { version = "2.3.1" }
chrono = { version = "0.4.23", default-features = false, features = ["clock"] }
clap = { version = "4.1.8", features = ["derive"] }
colored = { version = "2.0.0" }
filetime = { version = "0.2.20" }
glob = { version = "0.3.1" }
globset = { version = "0.4.10" }
ignore = { version = "0.4.20" }
insta = { version = "1.28.0" }
is-macro = { version = "0.2.2" }
libcst = { git = "https://github.com/charliermarsh/LibCST", rev = "80e4c1399f95e5beb532fdd1e209ad2dbb470438" }
once_cell = { version = "1.16.0" }
regex = { version = "1.6.0" }
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" }
path-absolutize = { version = "3.0.14" }
proc-macro2 = { version = "1.0.51" }
quote = { version = "1.0.23" }
regex = { version = "1.7.1" }
rustc-hash = { version = "1.1.0" }
rustpython-common = { git = "https://github.com/RustPython/RustPython.git", rev = "aa8336ee94492b52458ed8e1517238e5c6c2914c" }
rustpython-parser = { features = ["lalrpop"], git = "https://github.com/RustPython/RustPython.git", rev = "aa8336ee94492b52458ed8e1517238e5c6c2914c" }
schemars = { version = "0.8.11" }
serde = { version = "1.0.147", features = ["derive"] }
serde_json = { version = "1.0.87" }
schemars = { version = "0.8.12" }
serde = { version = "1.0.152", features = ["derive"] }
serde_json = { version = "1.0.93" }
shellexpand = { version = "3.0.0" }
similar = { version = "2.2.1", features = ["inline"] }
smallvec = { version = "1.10.0" }
strum = { version = "0.24.1", features = ["strum_macros"] }
strum_macros = { version = "0.24.3" }
toml = { version = "0.6.0" }
syn = { version = "2.0.15" }
test-case = { version = "3.0.0" }
toml = { version = "0.7.2" }
# v0.0.1
libcst = { git = "https://github.com/charliermarsh/LibCST", rev = "80e4c1399f95e5beb532fdd1e209ad2dbb470438" }
# v0.0.3
ruff_text_size = { git = "https://github.com/astral-sh/RustPython-Parser.git", rev = "ed3b4eb72b6e497bbdb4d19dec6621074d724130" }
# v0.0.3
rustpython-ast = { git = "https://github.com/astral-sh/RustPython-Parser.git", rev = "ed3b4eb72b6e497bbdb4d19dec6621074d724130" , default-features = false, features = ["all-nodes-with-ranges", "num-bigint"]}
# v0.0.3
rustpython-format = { git = "https://github.com/astral-sh/RustPython-Parser.git", rev = "ed3b4eb72b6e497bbdb4d19dec6621074d724130", default-features = false, features = ["num-bigint"] }
# v0.0.3
rustpython-literal = { git = "https://github.com/astral-sh/RustPython-Parser.git", rev = "ed3b4eb72b6e497bbdb4d19dec6621074d724130", default-features = false }
# v0.0.3
rustpython-parser = { git = "https://github.com/astral-sh/RustPython-Parser.git", rev = "ed3b4eb72b6e497bbdb4d19dec6621074d724130" , default-features = false, features = ["full-lexer", "all-nodes-with-ranges", "num-bigint"] }
[profile.release]
panic = "abort"
lto = "thin"
lto = "fat"
codegen-units = 1
opt-level = 3
[profile.dev.package.insta]
opt-level = 3
@@ -39,3 +74,9 @@ opt-level = 3
# https://github.com/bytecodealliance/wasm-tools/blob/b5c3d98e40590512a3b12470ef358d5c7b983b15/crates/wasmparser/src/limits.rs#L29
[profile.dev.package.rustpython-parser]
opt-level = 1
# Use the `--profile release-debug` flag to show symbols in release mode.
# e.g. `cargo build --profile release-debug`
[profile.release-debug]
inherits = "release"
debug = 1

163
LICENSE
View File

@@ -195,6 +195,15 @@ are:
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
"""
- flake8-gettext, licensed as follows:
"""
BSD Zero Clause License
Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
"""
- flake8-implicit-str-concat, licensed as follows:
"""
The MIT License (MIT)
@@ -345,6 +354,60 @@ are:
SOFTWARE.
"""
- flake8-slots, licensed as follows:
"""
Copyright (c) 2021 Dominic Davis-Foster
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
OR OTHER DEALINGS IN THE SOFTWARE.
"""
- flake8-todos, licensed as follows:
"""
Copyright (c) 2019 EclecticIQ. All rights reserved.
Copyright (c) 2020 Gram <gram@orsinium.dev>. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from this
software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""
- flake8-unused-arguments, licensed as follows:
"""
MIT License
@@ -393,7 +456,6 @@ are:
THE SOFTWARE.
"""
- autoflake, licensed as follows:
"""
Copyright (C) 2012-2018 Steven Myint
@@ -417,6 +479,31 @@ are:
SOFTWARE.
"""
- autotyping, licensed as follows:
"""
MIT License
Copyright (c) 2023 Jelle Zijlstra
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
"""
- Flake8, licensed as follows:
"""
== Flake8 License (MIT) ==
@@ -517,6 +604,30 @@ are:
THE SOFTWARE.
"""
- flynt, licensed as follows:
"""
MIT License
Copyright (c) 2019-2022 Ilya Kamenshchikov
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
"""
- isort, licensed as follows:
"""
@@ -726,6 +837,31 @@ are:
SOFTWARE.
"""
- flake8-async, licensed as follows:
"""
MIT License
Copyright (c) 2022 Cooper Lees
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
"""
- flake8-type-checking, licensed as follows:
"""
Copyright (c) 2021, Sondre Lillebø Gundersen
@@ -1063,6 +1199,31 @@ are:
- flake8-django, licensed under the GPL license.
- perflint, licensed as follows:
"""
MIT License
Copyright (c) 2022 Anthony Shaw
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
"""
- rust-analyzer/text-size, licensed under the MIT license:
"""
Permission is hereby granted, free of charge, to any

251
README.md
View File

@@ -2,11 +2,11 @@
# Ruff
[![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/charliermarsh/ruff/main/assets/badge/v1.json)](https://github.com/charliermarsh/ruff)
[![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/charliermarsh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)
[![image](https://img.shields.io/pypi/v/ruff.svg)](https://pypi.python.org/pypi/ruff)
[![image](https://img.shields.io/pypi/l/ruff.svg)](https://pypi.python.org/pypi/ruff)
[![image](https://img.shields.io/pypi/pyversions/ruff.svg)](https://pypi.python.org/pypi/ruff)
[![Actions status](https://github.com/charliermarsh/ruff/workflows/CI/badge.svg)](https://github.com/charliermarsh/ruff/actions)
[![Actions status](https://github.com/astral-sh/ruff/workflows/CI/badge.svg)](https://github.com/astral-sh/ruff/actions)
[**Discord**](https://discord.gg/c9MhzV8aU5) | [**Docs**](https://beta.ruff.rs/docs/) | [**Playground**](https://play.ruff.rs/)
@@ -24,17 +24,18 @@ An extremely fast Python linter, written in Rust.
<i>Linting the CPython codebase from scratch.</i>
</p>
- ⚡️ 10-100x faster than existing linters
- 🐍 Installable via `pip`
- 🛠️ `pyproject.toml` support
- 🤝 Python 3.11 compatibility
- 📦 Built-in caching, to avoid re-analyzing unchanged files
- 🔧 Autofix support, for automatic error correction (e.g., automatically remove unused imports)
- 📏 Over [500 built-in rules](https://beta.ruff.rs/docs/rules/)
- ⚖️ [Near-parity](https://beta.ruff.rs/docs/faq/#how-does-ruff-compare-to-flake8) with the built-in Flake8 rule set
- 🔌 Native re-implementations of dozens of Flake8 plugins, like flake8-bugbear
- ⌨️ First-party editor integrations for [VS Code](https://github.com/charliermarsh/ruff-vscode) and [more](https://github.com/charliermarsh/ruff-lsp)
- 🌎 Monorepo-friendly, with [hierarchical and cascading configuration](https://beta.ruff.rs/docs/configuration/#pyprojecttoml-discovery)
- ⚡️ 10-100x faster than existing linters
- 🐍 Installable via `pip`
- 🛠️ `pyproject.toml` support
- 🤝 Python 3.11 compatibility
- 📦 Built-in caching, to avoid re-analyzing unchanged files
- 🔧 Autofix support, for automatic error correction (e.g., automatically remove unused imports)
- 📏 Over [500 built-in rules](https://beta.ruff.rs/docs/rules/)
- ⚖️ [Near-parity](https://beta.ruff.rs/docs/faq/#how-does-ruff-compare-to-flake8) with the
built-in Flake8 rule set
- 🔌 Native re-implementations of dozens of Flake8 plugins, like flake8-bugbear
- ⌨️ First-party editor integrations for [VS Code](https://github.com/astral-sh/ruff-vscode) and [more](https://github.com/astral-sh/ruff-lsp)
- 🌎 Monorepo-friendly, with [hierarchical and cascading configuration](https://beta.ruff.rs/docs/configuration/#pyprojecttoml-discovery)
Ruff aims to be orders of magnitude faster than alternative tools while integrating more
functionality behind a single, common interface.
@@ -47,16 +48,16 @@ all while executing tens or hundreds of times faster than any individual tool.
Ruff is extremely actively developed and used in major open-source projects like:
- [pandas](https://github.com/pandas-dev/pandas)
- [FastAPI](https://github.com/tiangolo/fastapi)
- [Transformers (Hugging Face)](https://github.com/huggingface/transformers)
- [Apache Airflow](https://github.com/apache/airflow)
- [FastAPI](https://github.com/tiangolo/fastapi)
- [Hugging Face](https://github.com/huggingface/transformers)
- [Pandas](https://github.com/pandas-dev/pandas)
- [SciPy](https://github.com/scipy/scipy)
...and many more.
Read the [launch blog post](https://notes.crmarsh.com/python-tooling-could-be-much-much-faster) or
the most recent [project update](https://notes.crmarsh.com/ruff-the-first-200-releases).
Ruff is backed by [Astral](https://astral.sh). Read the [launch post](https://astral.sh/blog/announcing-astral-the-company-behind-ruff),
or the original [project announcement](https://notes.crmarsh.com/python-tooling-could-be-much-much-faster).
## Testimonials
@@ -84,9 +85,10 @@ of [Conda](https://docs.conda.io/en/latest/):
[**Timothy Crosley**](https://twitter.com/timothycrosley/status/1606420868514877440),
creator of [isort](https://github.com/PyCQA/isort):
> Just switched my first project to Ruff. Only one downside so far: it's so fast I couldn't believe it was working till I intentionally introduced some errors.
> Just switched my first project to Ruff. Only one downside so far: it's so fast I couldn't believe
> it was working till I intentionally introduced some errors.
[**Tim Abbott**](https://github.com/charliermarsh/ruff/issues/465#issuecomment-1317400028), lead
[**Tim Abbott**](https://github.com/astral-sh/ruff/issues/465#issuecomment-1317400028), lead
developer of [Zulip](https://github.com/zulip/zulip):
> This is just ridiculously fast... `ruff` is amazing.
@@ -135,15 +137,29 @@ ruff check path/to/code/to/file.py # Lint `file.py`
Ruff can also be used as a [pre-commit](https://pre-commit.com) hook:
```yaml
- repo: https://github.com/charliermarsh/ruff-pre-commit
- repo: https://github.com/astral-sh/ruff-pre-commit
# Ruff version.
rev: 'v0.0.253'
rev: v0.0.273
hooks:
- id: ruff
```
Ruff can also be used as a [VS Code extension](https://github.com/charliermarsh/ruff-vscode) or
alongside any other editor through the [Ruff LSP](https://github.com/charliermarsh/ruff-lsp).
Ruff can also be used as a [VS Code extension](https://github.com/astral-sh/ruff-vscode) or
alongside any other editor through the [Ruff LSP](https://github.com/astral-sh/ruff-lsp).
Ruff can also be used as a [GitHub Action](https://github.com/features/actions) via
[`ruff-action`](https://github.com/chartboost/ruff-action):
```yaml
name: Ruff
on: [ push, pull_request ]
jobs:
ruff:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: chartboost/ruff-action@v1
```
### Configuration
@@ -160,7 +176,7 @@ select = ["E", "F"]
ignore = []
# Allow autofix for all enabled rules (when `--fix`) is provided.
fixable = ["A", "B", "C", "D", "E", "F", "..."]
fixable = ["A", "B", "C", "D", "E", "F", "G", "I", "N", "Q", "S", "T", "W", "ANN", "ARG", "BLE", "COM", "DJ", "DTZ", "EM", "ERA", "EXE", "FBT", "ICN", "INP", "ISC", "NPY", "PD", "PGH", "PIE", "PL", "PT", "PTH", "PYI", "RET", "RSE", "RUF", "SIM", "SLF", "TCH", "TID", "TRY", "UP", "YTT"]
unfixable = []
# Exclude a variety of commonly ignored directories.
@@ -169,6 +185,7 @@ exclude = [
".direnv",
".eggs",
".git",
".git-rewrite",
".hg",
".mypy_cache",
".nox",
@@ -229,6 +246,62 @@ catches a wide variety of common errors (like unused imports) with zero configur
<!-- End section: Rules -->
Beyond the defaults, Ruff re-implements some of the most popular Flake8 plugins and related code
quality tools, including:
- [autoflake](https://pypi.org/project/autoflake/)
- [eradicate](https://pypi.org/project/eradicate/)
- [flake8-2020](https://pypi.org/project/flake8-2020/)
- [flake8-annotations](https://pypi.org/project/flake8-annotations/)
- [flake8-async](https://pypi.org/project/flake8-async)
- [flake8-bandit](https://pypi.org/project/flake8-bandit/) ([#1646](https://github.com/astral-sh/ruff/issues/1646))
- [flake8-blind-except](https://pypi.org/project/flake8-blind-except/)
- [flake8-boolean-trap](https://pypi.org/project/flake8-boolean-trap/)
- [flake8-bugbear](https://pypi.org/project/flake8-bugbear/)
- [flake8-builtins](https://pypi.org/project/flake8-builtins/)
- [flake8-commas](https://pypi.org/project/flake8-commas/)
- [flake8-comprehensions](https://pypi.org/project/flake8-comprehensions/)
- [flake8-copyright](https://pypi.org/project/flake8-copyright/)
- [flake8-datetimez](https://pypi.org/project/flake8-datetimez/)
- [flake8-debugger](https://pypi.org/project/flake8-debugger/)
- [flake8-django](https://pypi.org/project/flake8-django/)
- [flake8-docstrings](https://pypi.org/project/flake8-docstrings/)
- [flake8-eradicate](https://pypi.org/project/flake8-eradicate/)
- [flake8-errmsg](https://pypi.org/project/flake8-errmsg/)
- [flake8-executable](https://pypi.org/project/flake8-executable/)
- [flake8-future-annotations](https://pypi.org/project/flake8-future-annotations/)
- [flake8-gettext](https://pypi.org/project/flake8-gettext/)
- [flake8-implicit-str-concat](https://pypi.org/project/flake8-implicit-str-concat/)
- [flake8-import-conventions](https://github.com/joaopalmeiro/flake8-import-conventions)
- [flake8-logging-format](https://pypi.org/project/flake8-logging-format/)
- [flake8-no-pep420](https://pypi.org/project/flake8-no-pep420)
- [flake8-pie](https://pypi.org/project/flake8-pie/)
- [flake8-print](https://pypi.org/project/flake8-print/)
- [flake8-pyi](https://pypi.org/project/flake8-pyi/)
- [flake8-pytest-style](https://pypi.org/project/flake8-pytest-style/)
- [flake8-quotes](https://pypi.org/project/flake8-quotes/)
- [flake8-raise](https://pypi.org/project/flake8-raise/)
- [flake8-return](https://pypi.org/project/flake8-return/)
- [flake8-self](https://pypi.org/project/flake8-self/)
- [flake8-simplify](https://pypi.org/project/flake8-simplify/)
- [flake8-slots](https://pypi.org/project/flake8-slots/)
- [flake8-super](https://pypi.org/project/flake8-super/)
- [flake8-tidy-imports](https://pypi.org/project/flake8-tidy-imports/)
- [flake8-todos](https://pypi.org/project/flake8-todos/)
- [flake8-type-checking](https://pypi.org/project/flake8-type-checking/)
- [flake8-use-pathlib](https://pypi.org/project/flake8-use-pathlib/)
- [flynt](https://pypi.org/project/flynt/) ([#2102](https://github.com/astral-sh/ruff/issues/2102))
- [isort](https://pypi.org/project/isort/)
- [mccabe](https://pypi.org/project/mccabe/)
- [pandas-vet](https://pypi.org/project/pandas-vet/)
- [pep8-naming](https://pypi.org/project/pep8-naming/)
- [pydocstyle](https://pypi.org/project/pydocstyle/)
- [pygrep-hooks](https://github.com/pre-commit/pygrep-hooks)
- [pylint-airflow](https://pypi.org/project/pylint-airflow/)
- [pyupgrade](https://pypi.org/project/pyupgrade/)
- [tryceratops](https://pypi.org/project/tryceratops/)
- [yesqa](https://pypi.org/project/yesqa/)
For a complete enumeration of the supported rules, see [_Rules_](https://beta.ruff.rs/docs/rules/).
## Contributing
@@ -240,8 +313,8 @@ You can also join us on [**Discord**](https://discord.gg/c9MhzV8aU5).
## Support
Having trouble? Check out the existing issues on [**GitHub**](https://github.com/charliermarsh/ruff/issues),
or feel free to [**open a new one**](https://github.com/charliermarsh/ruff/issues/new).
Having trouble? Check out the existing issues on [**GitHub**](https://github.com/astral-sh/ruff/issues),
or feel free to [**open a new one**](https://github.com/astral-sh/ruff/issues/new).
You can also ask for help on [**Discord**](https://discord.gg/c9MhzV8aU5).
@@ -263,50 +336,108 @@ and again draws on both the APIs and implementation details of [Rome](https://gi
Ruff is also influenced by a number of tools outside the Python ecosystem, like
[Clippy](https://github.com/rust-lang/rust-clippy) and [ESLint](https://github.com/eslint/eslint).
Ruff is the beneficiary of a large number of [contributors](https://github.com/charliermarsh/ruff/graphs/contributors).
Ruff is the beneficiary of a large number of [contributors](https://github.com/astral-sh/ruff/graphs/contributors).
Ruff is released under the MIT license.
## Who's Using Ruff?
Ruff is used in a number of major open-source projects, including:
Ruff is used by a number of major open-source projects and companies, including:
- [pandas](https://github.com/pandas-dev/pandas)
- [FastAPI](https://github.com/tiangolo/fastapi)
- [Transformers (Hugging Face)](https://github.com/huggingface/transformers)
- [Diffusers (Hugging Face)](https://github.com/huggingface/diffusers)
- Amazon ([AWS SAM](https://github.com/aws/serverless-application-model))
- [Apache Airflow](https://github.com/apache/airflow)
- [SciPy](https://github.com/scipy/scipy)
- [Zulip](https://github.com/zulip/zulip)
- [Bokeh](https://github.com/bokeh/bokeh)
- [Pydantic](https://github.com/pydantic/pydantic)
- [Dagster](https://github.com/dagster-io/dagster)
- [Dagger](https://github.com/dagger/dagger)
- [Sphinx](https://github.com/sphinx-doc/sphinx)
- [Hatch](https://github.com/pypa/hatch)
- [PDM](https://github.com/pdm-project/pdm)
- [Jupyter](https://github.com/jupyter-server/jupyter_server)
- [Great Expectations](https://github.com/great-expectations/great_expectations)
- [ONNX](https://github.com/onnx/onnx)
- [Polars](https://github.com/pola-rs/polars)
- [Ibis](https://github.com/ibis-project/ibis)
- [Synapse (Matrix)](https://github.com/matrix-org/synapse)
- [SnowCLI (Snowflake)](https://github.com/Snowflake-Labs/snowcli)
- [Dispatch (Netflix)](https://github.com/Netflix/dispatch)
- [Saleor](https://github.com/saleor/saleor)
- [Pynecone](https://github.com/pynecone-io/pynecone)
- [OpenBB](https://github.com/OpenBB-finance/OpenBBTerminal)
- [Home Assistant](https://github.com/home-assistant/core)
- [Pylint](https://github.com/PyCQA/pylint)
- [Cryptography (PyCA)](https://github.com/pyca/cryptography)
- [cibuildwheel (PyPA)](https://github.com/pypa/cibuildwheel)
- [build (PyPA)](https://github.com/pypa/build)
- AstraZeneca ([Magnus](https://github.com/AstraZeneca/magnus-core))
- Benchling ([Refac](https://github.com/benchling/refac))
- [Babel](https://github.com/python-babel/babel)
- [Bokeh](https://github.com/bokeh/bokeh)
- [Cryptography (PyCA)](https://github.com/pyca/cryptography)
- [DVC](https://github.com/iterative/dvc)
- [Dagger](https://github.com/dagger/dagger)
- [Dagster](https://github.com/dagster-io/dagster)
- [FastAPI](https://github.com/tiangolo/fastapi)
- [Gradio](https://github.com/gradio-app/gradio)
- [Great Expectations](https://github.com/great-expectations/great_expectations)
- Hugging Face ([Transformers](https://github.com/huggingface/transformers),
[Datasets](https://github.com/huggingface/datasets),
[Diffusers](https://github.com/huggingface/diffusers))
- [Hatch](https://github.com/pypa/hatch)
- [Home Assistant](https://github.com/home-assistant/core)
- [Ibis](https://github.com/ibis-project/ibis)
- [Jupyter](https://github.com/jupyter-server/jupyter_server)
- [LangChain](https://github.com/hwchase17/langchain)
- [LlamaIndex](https://github.com/jerryjliu/llama_index)
- Matrix ([Synapse](https://github.com/matrix-org/synapse))
- Meltano ([Meltano CLI](https://github.com/meltano/meltano), [Singer SDK](https://github.com/meltano/sdk))
- Modern Treasury ([Python SDK](https://github.com/Modern-Treasury/modern-treasury-python-sdk))
- Mozilla ([Firefox](https://github.com/mozilla/gecko-dev))
- [MegaLinter](https://github.com/oxsecurity/megalinter)
- Microsoft ([Semantic Kernel](https://github.com/microsoft/semantic-kernel),
[ONNX Runtime](https://github.com/microsoft/onnxruntime),
[LightGBM](https://github.com/microsoft/LightGBM))
- Netflix ([Dispatch](https://github.com/Netflix/dispatch))
- [Neon](https://github.com/neondatabase/neon)
- [ONNX](https://github.com/onnx/onnx)
- [OpenBB](https://github.com/OpenBB-finance/OpenBBTerminal)
- [PDM](https://github.com/pdm-project/pdm)
- [PaddlePaddle](https://github.com/PaddlePaddle/Paddle)
- [Pandas](https://github.com/pandas-dev/pandas)
- [Poetry](https://github.com/python-poetry/poetry)
- [Polars](https://github.com/pola-rs/polars)
- [PostHog](https://github.com/PostHog/posthog)
- Prefect ([Python SDK](https://github.com/PrefectHQ/prefect), [Marvin](https://github.com/PrefectHQ/marvin))
- [PyInstaller](https://github.com/pyinstaller/pyinstaller)
- [PyTorch](https://github.com/pytorch/pytorch)
- [Pydantic](https://github.com/pydantic/pydantic)
- [Pylint](https://github.com/PyCQA/pylint)
- [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))
- [Saleor](https://github.com/saleor/saleor)
- [SciPy](https://github.com/scipy/scipy)
- [Sphinx](https://github.com/sphinx-doc/sphinx)
- [Stable Baselines3](https://github.com/DLR-RM/stable-baselines3)
- [Litestar](https://litestar.dev/)
- [The Algorithms](https://github.com/TheAlgorithms/Python)
- [Vega-Altair](https://github.com/altair-viz/altair)
- WordPress ([Openverse](https://github.com/WordPress/openverse))
- [ZenML](https://github.com/zenml-io/zenml)
- [Zulip](https://github.com/zulip/zulip)
- [build (PyPA)](https://github.com/pypa/build)
- [cibuildwheel (PyPA)](https://github.com/pypa/cibuildwheel)
- [delta-rs](https://github.com/delta-io/delta-rs)
- [featuretools](https://github.com/alteryx/featuretools)
- [meson-python](https://github.com/mesonbuild/meson-python)
- [ZenML](https://github.com/zenml-io/zenml)
- [delta-rs](https://github.com/delta-io/delta-rs)
- [nox](https://github.com/wntrblm/nox)
### Show Your Support
If you're using Ruff, consider adding the Ruff badge to project's `README.md`:
```md
[![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/charliermarsh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)
```
...or `README.rst`:
```rst
.. 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
```
...or, as HTML:
```html
<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
MIT
<div align="center">
<a target="_blank" href="https://astral.sh" style="background:none">
<img src="https://raw.githubusercontent.com/charliermarsh/ruff/main/assets/svg/Astral.svg">
</a>
</div>

View File

@@ -1,7 +1,11 @@
[files]
extend-exclude = ["snapshots", "black"]
extend-exclude = ["resources", "snapshots"]
[default.extend-words]
trivias = "trivias"
hel = "hel"
whos = "whos"
spawnve = "spawnve"
ned = "ned"
poit = "poit"
BA = "BA" # acronym for "Bad Allowed", used in testing.

8
assets/badge/v2.json Normal file
View File

@@ -0,0 +1,8 @@
{
"label": "",
"message": "Ruff",
"logoSvg": "<svg width=\"510\" height=\"622\" viewBox=\"0 0 510 622\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\"><path fill-rule=\"evenodd\" clip-rule=\"evenodd\" d=\"M206.701 0C200.964 0 196.314 4.64131 196.314 10.3667V41.4667C196.314 47.192 191.663 51.8333 185.927 51.8333H156.843C151.107 51.8333 146.456 56.4746 146.456 62.2V145.133C146.456 150.859 141.806 155.5 136.069 155.5H106.986C101.249 155.5 96.5988 160.141 96.5988 165.867V222.883C96.5988 228.609 91.9484 233.25 86.2118 233.25H57.1283C51.3917 233.25 46.7413 237.891 46.7413 243.617V300.633C46.7413 306.359 42.0909 311 36.3544 311H10.387C4.6504 311 0 315.641 0 321.367V352.467C0 358.192 4.6504 362.833 10.387 362.833H145.418C151.154 362.833 155.804 367.475 155.804 373.2V430.217C155.804 435.942 151.154 440.583 145.418 440.583H116.334C110.597 440.583 105.947 445.225 105.947 450.95V507.967C105.947 513.692 101.297 518.333 95.5601 518.333H66.4766C60.74 518.333 56.0896 522.975 56.0896 528.7V611.633C56.0896 617.359 60.74 622 66.4766 622H149.572C155.309 622 159.959 617.359 159.959 611.633V570.167H201.507C207.244 570.167 211.894 565.525 211.894 559.8V528.7C211.894 522.975 216.544 518.333 222.281 518.333H251.365C257.101 518.333 261.752 513.692 261.752 507.967V476.867C261.752 471.141 266.402 466.5 272.138 466.5H301.222C306.959 466.5 311.609 461.859 311.609 456.133V425.033C311.609 419.308 316.259 414.667 321.996 414.667H351.079C356.816 414.667 361.466 410.025 361.466 404.3V373.2C361.466 367.475 366.117 362.833 371.853 362.833H400.937C406.673 362.833 411.324 358.192 411.324 352.467V321.367C411.324 315.641 415.974 311 421.711 311H450.794C456.531 311 461.181 306.359 461.181 300.633V217.7C461.181 211.975 456.531 207.333 450.794 207.333H420.672C414.936 207.333 410.285 202.692 410.285 196.967V165.867C410.285 160.141 414.936 155.5 420.672 155.5H449.756C455.492 155.5 460.143 150.859 460.143 145.133V114.033C460.143 108.308 464.793 103.667 470.53 103.667H499.613C505.35 103.667 510 99.0253 510 93.3V10.3667C510 4.64132 505.35 0 499.613 0H206.701ZM168.269 440.583C162.532 440.583 157.882 445.225 157.882 450.95V507.967C157.882 513.692 153.231 518.333 147.495 518.333H118.411C112.675 518.333 108.024 522.975 108.024 528.7V559.8C108.024 565.525 112.675 570.167 118.411 570.167H159.959V528.7C159.959 522.975 164.61 518.333 170.346 518.333H199.43C205.166 518.333 209.817 513.692 209.817 507.967V476.867C209.817 471.141 214.467 466.5 220.204 466.5H249.287C255.024 466.5 259.674 461.859 259.674 456.133V425.033C259.674 419.308 264.325 414.667 270.061 414.667H299.145C304.881 414.667 309.532 410.025 309.532 404.3V373.2C309.532 367.475 314.182 362.833 319.919 362.833H349.002C354.739 362.833 359.389 358.192 359.389 352.467V321.367C359.389 315.641 364.039 311 369.776 311H398.859C404.596 311 409.246 306.359 409.246 300.633V269.533C409.246 263.808 404.596 259.167 398.859 259.167H318.88C313.143 259.167 308.493 254.525 308.493 248.8V217.7C308.493 211.975 313.143 207.333 318.88 207.333H347.963C353.7 207.333 358.35 202.692 358.35 196.967V165.867C358.35 160.141 363.001 155.5 368.737 155.5H397.821C403.557 155.5 408.208 150.859 408.208 145.133V114.033C408.208 108.308 412.858 103.667 418.595 103.667H447.678C453.415 103.667 458.065 99.0253 458.065 93.3V62.2C458.065 56.4746 453.415 51.8333 447.678 51.8333H208.778C203.041 51.8333 198.391 56.4746 198.391 62.2V145.133C198.391 150.859 193.741 155.5 188.004 155.5H158.921C153.184 155.5 148.534 160.141 148.534 165.867V222.883C148.534 228.609 143.883 233.25 138.147 233.25H109.063C103.327 233.25 98.6762 237.891 98.6762 243.617V300.633C98.6762 306.359 103.327 311 109.063 311H197.352C203.089 311 207.739 315.641 207.739 321.367V430.217C207.739 435.942 203.089 440.583 197.352 440.583H168.269Z\" fill=\"#D7FF64\"/></svg>",
"logoWidth": 10,
"labelColor": "grey",
"color": "#261230"
}

BIN
assets/png/Astral.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

24
assets/svg/Astral.svg Normal file
View File

@@ -0,0 +1,24 @@
<svg width="139" height="24" viewBox="0 0 139 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="138.764" height="24" rx="2.18182" fill="#261230"/>
<path
d="M8.72798 15.2726H9.91316V11.8697L9.6887 10.4062L9.8952 10.3343L12.1309 15.1649L14.3486 10.3343L14.5461 10.4062L14.3486 11.8607V15.2726H15.5248V8.72714H13.9535L12.2117 12.7137H12.0142L10.2723 8.72714H8.72798V15.2726Z"
fill="#D7FF64"/>
<path
d="M22.3432 15.2726H23.6631L21.3017 8.72714H19.7574L17.4589 15.2726H18.7069L19.1558 13.9797H21.9033L22.3432 15.2726ZM19.497 13.0279L19.901 11.8607L20.4308 10.0021H20.6463L21.176 11.8607L21.5711 13.0279H19.497Z"
fill="#D7FF64"/>
<path
d="M25.4209 15.2726H28.1234C30.1077 15.2726 30.9876 14.1413 30.9876 12.0044C30.9876 9.92131 30.1706 8.72714 28.1234 8.72714H25.4209V15.2726ZM26.624 14.2131V9.77765H28.0965C29.147 9.77765 29.7306 10.1907 29.7306 11.4477V12.5521C29.7306 13.6923 29.2817 14.2131 28.0965 14.2131H26.624Z"
fill="#D7FF64"/>
<path
d="M33.079 15.2726H37.6491V14.2131H34.2822V12.3815H37.2002V11.3938H34.2822V9.77765H37.6491V8.72714H33.079V15.2726Z"
fill="#D7FF64"/>
<path
d="M42.923 15.2726H46.2451C47.4572 15.2726 48.2025 14.5812 48.2025 13.5487C48.2025 12.7675 47.8343 12.175 47.0532 11.9954V11.7799C47.6637 11.5734 48.0319 11.0436 48.0319 10.3433C48.0319 9.38259 47.4572 8.72714 46.281 8.72714H42.923V15.2726ZM44.0992 11.4746V9.65195H45.9578C46.4875 9.65195 46.7928 9.92131 46.7928 10.3523V10.7653C46.7928 11.1873 46.4965 11.4746 45.9758 11.4746H44.0992ZM44.0992 14.3388V12.3904H46.0296C46.5863 12.3904 46.9365 12.6418 46.9365 13.1806V13.5666C46.9365 14.0425 46.5684 14.3388 45.9309 14.3388H44.0992Z"
fill="#D7FF64"/>
<path
d="M49.6959 8.72714L52.174 12.579V14.1952H50.1898V15.2726H53.3772V12.579L55.8553 8.72714H54.4456L53.5119 10.2535L52.8744 11.3759H52.6679L52.0483 10.2715L51.1056 8.72714H49.6959Z"
fill="#D7FF64"/>
<path fill-rule="evenodd" clip-rule="evenodd"
d="M74.1824 7.63626C74.1824 7.03377 74.6708 6.54535 75.2733 6.54535H84.0006C84.6031 6.54535 85.0915 7.03377 85.0915 7.63626V9.81808H80.0733V8.94535H79.2006V10.6908H84.0006C84.6031 10.6908 85.0915 11.1792 85.0915 11.7817V16.3635C85.0915 16.966 84.6031 17.4544 84.0006 17.4544H75.2733C74.6708 17.4544 74.1824 16.966 74.1824 16.3635V14.1817L79.2006 14.1817V15.0544H80.0733V13.309L75.2733 13.309C74.6708 13.309 74.1824 12.8206 74.1824 12.2181V7.63626ZM63.4912 6.54545C62.8887 6.54545 62.4003 7.03387 62.4003 7.63636V17.4545H67.4185V14.1818H68.2912V17.4545H73.3094V7.63636C73.3094 7.03387 72.821 6.54545 72.2185 6.54545H63.4912ZM69.164 10.6909V11.5636H66.5458V10.6909H69.164ZM110.619 6.54545C110.016 6.54545 109.528 7.03387 109.528 7.63636V17.4545H114.546V14.1818H115.419V17.4545H120.437V7.63636C120.437 7.03387 119.948 6.54545 119.346 6.54545H110.619ZM116.291 10.6909V11.5636H113.673V10.6909H116.291ZM91.8549 8.29091H96.8731V11.3455C96.8731 11.9479 96.3847 12.4364 95.7822 12.4364H91.8549V13.3091H96.8731V17.4545H87.9276C87.3251 17.4545 86.8367 16.9661 86.8367 16.3636V12.4364H85.964V8.29091H86.8367V6.54545H91.8549V8.29091ZM108.655 7.63636C108.655 7.03387 108.166 6.54545 107.564 6.54545H97.7458V17.4545H102.764V14.1818H103.637V17.4545H108.655V13.3091H106.473V12.4364H107.564C108.166 12.4364 108.655 11.9479 108.655 11.3455V7.63636ZM104.509 10.6909V11.5636H101.891V10.6909H104.509ZM132.218 13.3091L126.327 13.3091V6.54547L121.309 6.54547V17.4546H132.218V13.3091Z"
fill="#D7FF64"/>
</svg>

After

Width:  |  Height:  |  Size: 3.4 KiB

View File

@@ -1,17 +1,26 @@
[package]
name = "flake8-to-ruff"
version = "0.0.253"
version = "0.0.273"
description = """
Convert Flake8 configuration files to Ruff configuration files.
"""
authors = { workspace = true }
edition = { workspace = true }
rust-version = { workspace = true }
homepage = { workspace = true }
documentation = { workspace = true }
repository = { workspace = true }
license = { workspace = true }
[dependencies]
ruff = { path = "../ruff", default-features = false }
anyhow = { workspace = true }
clap = { workspace = true }
colored = { version = "2.0.0" }
colored = { workspace = true }
configparser = { version = "3.0.2" }
once_cell = { workspace = true }
regex = { workspace = true }
ruff = { path = "../ruff", default-features = false }
rustc-hash = { workspace = true }
serde = { workspace = true }
serde_json = { workspace = true }

View File

@@ -1,7 +1,7 @@
# flake8-to-ruff
Convert existing Flake8 configuration files (`setup.cfg`, `tox.ini`, or `.flake8`) for use with
[Ruff](https://github.com/charliermarsh/ruff).
[Ruff](https://github.com/astral-sh/ruff).
Generates a Ruff-compatible `pyproject.toml` section.
@@ -85,8 +85,9 @@ flake8-to-ruff path/to/.flake8 --plugin flake8-builtins --plugin flake8-quotes
ignore unsupported options in the `.flake8` file (or equivalent). (Similarly, Ruff has a few
configuration options that don't exist in Flake8.)
1. Ruff will omit any rule codes that are unimplemented or unsupported by Ruff, including rule
codes from unsupported plugins. (See the [Ruff README](https://github.com/charliermarsh/ruff#user-content-how-does-ruff-compare-to-flake8)
for the complete list of supported plugins.)
codes from unsupported plugins. (See the
[documentation](https://beta.ruff.rs/docs/faq/#how-does-ruff-compare-to-flake8) for the complete
list of supported plugins.)
## License
@@ -95,4 +96,4 @@ MIT
## Contributing
Contributions are welcome and hugely appreciated. To get started, check out the
[contributing guidelines](https://github.com/charliermarsh/ruff/blob/main/CONTRIBUTING.md).
[contributing guidelines](https://github.com/astral-sh/ruff/blob/main/CONTRIBUTING.md).

View File

@@ -23,10 +23,10 @@ description = "Convert existing Flake8 configuration to Ruff."
requires-python = ">=3.7"
[project.urls]
repository = "https://github.com/charliermarsh/ruff#subdirectory=crates/flake8_to_ruff"
repository = "https://github.com/astral-sh/ruff#subdirectory=crates/flake8_to_ruff"
[build-system]
requires = ["maturin>=0.14,<0.15"]
requires = ["maturin>=1.0,<2.0"]
build-backend = "maturin"
[tool.maturin]

View File

@@ -46,8 +46,15 @@ fn main() -> Result<()> {
.map(|tool| ExternalConfig {
black: tool.black.as_ref(),
isort: tool.isort.as_ref(),
..Default::default()
})
.unwrap_or_default();
let external_config = ExternalConfig {
project: pyproject
.as_ref()
.and_then(|pyproject| pyproject.project.as_ref()),
..external_config
};
// Create Ruff's pyproject.toml section.
let pyproject = flake8_to_ruff::convert(&config, &external_config, args.plugin)?;

View File

@@ -1,83 +1,90 @@
[package]
name = "ruff"
version = "0.0.253"
authors = ["Charlie Marsh <charlie.r.marsh@gmail.com>"]
version = "0.0.273"
publish = false
authors = { workspace = true }
edition = { workspace = true }
rust-version = { workspace = true }
documentation = "https://github.com/charliermarsh/ruff"
homepage = "https://github.com/charliermarsh/ruff"
repository = "https://github.com/charliermarsh/ruff"
homepage = { workspace = true }
documentation = { workspace = true }
repository = { workspace = true }
license = { workspace = true }
readme = "README.md"
license = "MIT"
[lib]
name = "ruff"
crate-type = ["cdylib", "rlib"]
doctest = false
[dependencies]
ruff_cache = { path = "../ruff_cache" }
ruff_diagnostics = { path = "../ruff_diagnostics", features = ["serde"] }
ruff_macros = { path = "../ruff_macros" }
ruff_python = { path = "../ruff_python" }
ruff_python_whitespace = { path = "../ruff_python_whitespace" }
ruff_python_ast = { path = "../ruff_python_ast", features = ["serde"] }
ruff_python_semantic = { path = "../ruff_python_semantic" }
ruff_python_stdlib = { path = "../ruff_python_stdlib" }
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 }
bisection = { version = "0.1.0" }
bitflags = { version = "1.3.2" }
cfg-if = { version = "1.0.0" }
chrono = { version = "0.4.21", default-features = false, features = ["clock"] }
clap = { workspace = true, features = ["derive", "env", "string"] }
colored = { version = "2.0.0" }
derivative = { version = "2.2.0" }
dirs = { version = "4.0.0" }
bitflags = { workspace = true }
chrono = { workspace = true }
clap = { workspace = true, features = ["derive", "string"], optional = true }
colored = { workspace = true }
dirs = { version = "5.0.0" }
fern = { version = "0.6.1" }
glob = { version = "0.3.0" }
globset = { version = "0.4.9" }
ignore = { version = "0.4.18" }
imperative = { version = "1.0.3" }
glob = { workspace = true }
globset = { workspace = true }
ignore = { workspace = true }
imperative = { version = "1.0.4" }
is-macro = { workspace = true }
itertools = { workspace = true }
libcst = { workspace = true }
log = { version = "0.4.17" }
log = { workspace = true }
natord = { version = "1.0.9" }
nohash-hasher = { version = "0.2.0" }
num-bigint = { version = "0.4.3" }
num-traits = "0.2.15"
nohash-hasher = { workspace = true }
num-bigint = { workspace = true }
num-traits = { workspace = true }
once_cell = { workspace = true }
path-absolutize = { version = "3.0.14", features = ["once_cell_cache", "use_unix_paths_on_wasm"] }
path-absolutize = { workspace = true, features = [
"once_cell_cache",
"use_unix_paths_on_wasm",
] }
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 = "0.4.6"
result-like = { version = "0.4.6" }
rustc-hash = { workspace = true }
rustpython-common = { workspace = true }
rustpython-format = { workspace = true }
rustpython-parser = { workspace = true }
schemars = { workspace = true }
schemars = { workspace = true, optional = true }
semver = { version = "1.0.16" }
serde = { workspace = true }
shellexpand = { version = "3.0.0" }
smallvec = { version = "1.10.0" }
serde_json = { workspace = true }
serde_with = { version = "3.0.0" }
similar = { workspace = true }
shellexpand = { workspace = true }
smallvec = { workspace = true }
strum = { workspace = true }
strum_macros = { workspace = true }
textwrap = { version = "0.16.0" }
thiserror = { version = "1.0" }
titlecase = { version = "2.2.1" }
thiserror = { version = "1.0.38" }
toml = { workspace = true }
# https://docs.rs/getrandom/0.2.7/getrandom/#webassembly-support
[target.'cfg(all(target_family = "wasm", target_os = "unknown"))'.dependencies]
getrandom = { version = "0.2.7", features = ["js"] }
console_error_panic_hook = { version = "0.1.7" }
console_log = { version = "0.2.0" }
serde-wasm-bindgen = { version = "0.4" }
js-sys = { version = "0.3.60" }
wasm-bindgen = { version = "0.2.83" }
typed-arena = { version = "2.0.2" }
unicode-width = { version = "0.1.10" }
unicode_names2 = { version = "0.6.0", git = "https://github.com/youknowone/unicode_names2.git", rev = "4ce16aa85cbcdd9cc830410f1a72ef9a235f2fde" }
[dev-dependencies]
insta = { version = "1.19.0", features = ["yaml", "redactions"] }
test-case = { version = "2.2.2" }
wasm-bindgen-test = { version = "0.3.33" }
[target.'cfg(not(target_family = "wasm"))'.dev-dependencies]
criterion = { version = "0.4.0" }
insta = { workspace = true }
pretty_assertions = "1.3.0"
test-case = { workspace = true }
# Disable colored output in tests
colored = { workspace = true, features = ["no-color"] }
[features]
default = []
logical_lines = []
schemars = ["dep:schemars"]
jupyter_notebook = []

View File

@@ -2,3 +2,7 @@ avoid-*
do-not-*
uses-*
*-used
rewrite-*
prefer-*
consider-*
use-*

View File

@@ -0,0 +1,16 @@
from airflow.operators import PythonOperator
def my_callable():
pass
my_task = PythonOperator(task_id="my_task", callable=my_callable)
my_task_2 = PythonOperator(callable=my_callable, task_id="my_task_2")
incorrect_name = PythonOperator(task_id="my_task")
incorrect_name_2 = PythonOperator(callable=my_callable, task_id="my_task_2")
from my_module import MyClass
incorrect_name = MyClass(task_id="my_task")

View File

@@ -9,7 +9,13 @@ def foo(x, y, z):
print(x, y, z)
# This is a real comment.
# # This is a (nested) comment.
#return True
return False
#import os # noqa: ERA001
class A():
pass
# b = c

View File

@@ -1,4 +1,5 @@
from typing import Any, Type
from typing_extensions import override
# Error
def foo(a, b):
@@ -94,6 +95,31 @@ class Foo:
def foo(self: "Foo", a: int, *params: str, **options: Any) -> int:
pass
# ANN401
@override
def foo(self: "Foo", a: Any, *params: str, **options: str) -> int:
pass
# ANN401
@override
def foo(self: "Foo", a: int, *params: str, **options: str) -> Any:
pass
# ANN401
@override
def foo(self: "Foo", a: int, *params: Any, **options: Any) -> int:
pass
# ANN401
@override
def foo(self: "Foo", a: int, *params: Any, **options: str) -> int:
pass
# ANN401
@override
def foo(self: "Foo", a: int, *params: str, **options: Any) -> int:
pass
# OK
@classmethod
def foo(cls: Type["Foo"], a: int, b: int) -> int:

View File

@@ -0,0 +1,42 @@
class Foo:
def __str__(self):
...
def __repr__(self):
...
def __len__(self):
...
def __length_hint__(self):
...
def __init__(self):
...
def __del__(self):
...
def __bool__(self):
...
def __bytes__(self):
...
def __format__(self, format_spec):
...
def __contains__(self, item):
...
def __complex__(self):
...
def __int__(self):
...
def __float__(self):
...
def __index__(self):
...

View File

@@ -0,0 +1,23 @@
import urllib.request
import requests
import httpx
async def foo():
urllib.request.urlopen("http://example.com/foo/bar").read()
async def foo():
requests.get()
async def foo():
httpx.get()
async def foo():
requests.post()
async def foo():
httpx.post()

View File

@@ -0,0 +1,31 @@
import os
import subprocess
import time
async def foo():
open("foo")
async def foo():
time.sleep(1)
async def foo():
subprocess.run("foo")
async def foo():
subprocess.call("foo")
async def foo():
subprocess.foo(0)
async def foo():
os.wait4(10)
async def foo():
os.wait(12)

View File

@@ -0,0 +1,13 @@
import os
async def foo():
os.popen()
async def foo():
os.spawnl()
async def foo():
os.fspath("foo")

View File

@@ -1,11 +1,13 @@
# Error
assert True
assert True # S101
def fn():
x = 1
assert x == 1 # S101
assert x == 2 # S101
# Error
assert x == 1
# Error
assert x == 2
from typing import TYPE_CHECKING
if TYPE_CHECKING:
assert True # OK

View File

@@ -0,0 +1,3 @@
import pickle
pickle.loads()

View File

@@ -0,0 +1,3 @@
from telnetlib import Telnet
Telnet("localhost", 23)

View File

@@ -0,0 +1,3 @@
import paramiko
paramiko.exec_command('something; really; unsafe')

View File

@@ -0,0 +1,20 @@
from subprocess import Popen, call, check_call, check_output, run
# Check different Popen wrappers are checked.
Popen("true", shell=True)
call("true", shell=True)
check_call("true", shell=True)
check_output("true", shell=True)
run("true", shell=True)
# Check values that truthy values are treated as true.
Popen("true", shell=1)
Popen("true", shell=[1])
Popen("true", shell={1: 1})
Popen("true", shell=(1,))
# Check command argument looks unsafe.
var_string = "true"
Popen(var_string, shell=True)
Popen([var_string], shell=True)
Popen([var_string, ""], shell=True)

View File

@@ -0,0 +1,20 @@
from subprocess import Popen, call, check_call, check_output, run
# Different Popen wrappers are checked.
Popen("true", shell=False)
call("true", shell=False)
check_call("true", shell=False)
check_output("true", shell=False)
run("true", shell=False)
# Values that falsey values are treated as false.
Popen("true", shell=0)
Popen("true", shell=[])
Popen("true", shell={})
Popen("true", shell=None)
# Unknown values are treated as falsey.
Popen("true", shell=True if True else False)
# No value is also caught.
Popen("true")

View File

@@ -0,0 +1,5 @@
def foo(shell):
pass
foo(shell=True)

View File

@@ -0,0 +1,25 @@
import os
import commands
import popen2
# Check all shell functions.
os.system("true")
os.popen("true")
os.popen2("true")
os.popen3("true")
os.popen4("true")
popen2.popen2("true")
popen2.popen3("true")
popen2.popen4("true")
popen2.Popen3("true")
popen2.Popen4("true")
commands.getoutput("true")
commands.getstatusoutput("true")
# Check command argument looks unsafe.
var_string = "true"
os.system(var_string)
os.system([var_string])
os.system([var_string, ""])

View File

@@ -0,0 +1,20 @@
import os
# Check all shell functions.
os.execl("true")
os.execle("true")
os.execlp("true")
os.execlpe("true")
os.execv("true")
os.execve("true")
os.execvp("true")
os.execvpe("true")
os.spawnl("true")
os.spawnle("true")
os.spawnlp("true")
os.spawnlpe("true")
os.spawnv("true")
os.spawnve("true")
os.spawnvp("true")
os.spawnvpe("true")
os.startfile("true")

View File

@@ -0,0 +1,44 @@
import os
# Check all functions.
subprocess.Popen("true")
subprocess.call("true")
subprocess.check_call("true")
subprocess.check_output("true")
subprocess.run("true")
os.system("true")
os.popen("true")
os.popen2("true")
os.popen3("true")
os.popen4("true")
popen2.popen2("true")
popen2.popen3("true")
popen2.popen4("true")
popen2.Popen3("true")
popen2.Popen4("true")
commands.getoutput("true")
commands.getstatusoutput("true")
os.execl("true")
os.execle("true")
os.execlp("true")
os.execlpe("true")
os.execv("true")
os.execve("true")
os.execvp("true")
os.execvpe("true")
os.spawnl("true")
os.spawnle("true")
os.spawnlp("true")
os.spawnlpe("true")
os.spawnv("true")
os.spawnve("true")
os.spawnvp("true")
os.spawnvpe("true")
os.startfile("true")
# Check it does not fail for full paths.
os.system("/bin/ls")
os.system("./bin/ls")
os.system(["/bin/ls"])
os.system(["/bin/ls", "/tmp"])
os.system(r"C:\\bin\ls")

View File

@@ -74,8 +74,8 @@ def query40():
def query41():
return (
"SELECT *"
"FROM table"
"SELECT * "
"FROM table "
f"WHERE var = {var}"
)
@@ -84,7 +84,7 @@ query42 = cursor.execute("SELECT * FROM table WHERE var = %s" % var)
query43 = cursor.execute(f"SELECT * FROM table WHERE var = {var}")
query44 = cursor.execute("SELECT * FROM table WHERE var = {}".format(var))
query45 = cursor.executemany("SELECT * FROM table WHERE var = %s" % var, [])
# # pass
query = "SELECT * FROM table WHERE id = 1"
query = "DELETE FROM table WHERE id = 1"
@@ -93,3 +93,12 @@ query = "UPDATE table SET id = 1"
cursor.execute('SELECT * FROM table WHERE id = %s', var)
cursor.execute('SELECT * FROM table WHERE id = 1')
cursor.executemany('SELECT * FROM table WHERE id = %s', [var, var2])
# # INSERT without INTO (e.g. MySQL and derivatives)
query = "INSERT table VALUES (%s)" % (var,)
# # REPLACE (e.g. MySQL and derivatives, SQLite)
query = "REPLACE INTO table VALUES (%s)" % (var,)
query = "REPLACE table VALUES (%s)" % (var,)
query = "Deselect something that is not SQL even though it has a ' from ' somewhere in %s." % "there"

View File

@@ -0,0 +1,8 @@
import os
import subprocess
os.popen("chmod +w foo*")
subprocess.Popen("/bin/chown root: *", shell=True)
subprocess.Popen(["/usr/local/bin/rsync", "*", "some_where:"], shell=True)
subprocess.Popen("/usr/local/bin/rsync * no_injection_here:")
os.system("tar cf foo.tar bar/*")

View File

@@ -57,12 +57,16 @@ dict.fromkeys(("world",), True)
{}.deploy(True, False)
getattr(someobj, attrname, False)
mylist.index(True)
bool(False)
int(True)
str(int(False))
cfg.get("hello", True)
cfg.getint("hello", True)
cfg.getfloat("hello", True)
cfg.getboolean("hello", True)
os.set_blocking(0, False)
g_action.set_enabled(True)
settings.set_enable_developer_extras(True)
class Registry:
@@ -80,3 +84,6 @@ class Registry:
# FBT001: Boolean positional arg in function definition
def foo(self, value: bool) -> None:
pass
def foo(self) -> None:
object.__setattr__(self, "flag", True)

View File

@@ -1,7 +1,10 @@
import collections
import datetime as dt
from decimal import Decimal
from fractions import Fraction
import logging
import operator
from pathlib import Path
import random
import re
import time
@@ -156,15 +159,60 @@ def float_infinity_literal(value=float("1e999")):
pass
# But don't allow standard floats
def float_int_is_wrong(value=float(3)):
# Allow standard floats
def float_int_okay(value=float(3)):
pass
def float_str_not_inf_or_nan_is_wrong(value=float("3.14")):
def float_str_not_inf_or_nan_okay(value=float("3.14")):
pass
# Allow immutable str() value
def str_okay(value=str("foo")):
pass
# Allow immutable bool() value
def bool_okay(value=bool("bar")):
pass
# Allow immutable int() value
def int_okay(value=int("12")):
pass
# Allow immutable complex() value
def complex_okay(value=complex(1,2)):
pass
# Allow immutable Fraction() value
def fraction_okay(value=Fraction(1,2)):
pass
# Allow decimals
def decimal_okay(value=Decimal("0.1")):
pass
# Allow dates
def date_okay(value=dt.date(2023, 3, 27)):
pass
# Allow datetimes
def datetime_okay(value=dt.datetime(2023, 3, 27, 13, 51, 59)):
pass
# Allow timedeltas
def timedelta_okay(value=dt.timedelta(hours=1)):
pass
# Allow paths
def path_okay(value=Path(".")):
pass
# B006 and B008
# We should handle arbitrary nesting of these B008.
def nested_combo(a=[float(3), dt.datetime.now()]):

View File

@@ -73,7 +73,18 @@ def f():
def f():
# Fixable.
# Unfixable.
for foo, bar, baz in (["1", "2", "3"],):
if foo or baz:
break
else:
bar = 1
print(bar)
def f():
# Unfixable (false negative) due to usage of `bar` outside of loop.
for foo, bar, baz in (["1", "2", "3"],):
if foo or baz:
break
@@ -85,4 +96,4 @@ def f():
# Unfixable due to trailing underscore (`_line_` wouldn't be considered an ignorable
# variable name).
for line_ in range(self.header_lines):
fp.readline()
fp.readline()

View File

@@ -1,9 +1,10 @@
"""
Should emit:
B017 - on lines 20
B017 - on lines 23 and 41
"""
import asyncio
import unittest
import pytest
CONSTANT = True
@@ -34,3 +35,14 @@ class Foobar(unittest.TestCase):
def raises_with_absolute_reference(self):
with self.assertRaises(asyncio.CancelledError):
Foo()
def test_pytest_raises():
with pytest.raises(Exception):
raise ValueError("Hello")
with pytest.raises(Exception, "hello"):
raise ValueError("This is fine")
with pytest.raises(Exception, match="hello"):
raise ValueError("This is also fine")

View File

@@ -57,3 +57,9 @@ def foo3():
def foo4():
...
def foo5():
foo.bar # Attribute (raise)
object().__class__ # Attribute (raise)
"foo" + "bar" # BinOp (raise)

View File

@@ -172,3 +172,14 @@ def iter_f(names):
if False:
return [lambda: i for i in range(3)] # error
for val in range(3):
def make_func(val=val):
def tmp():
return print(val)
return tmp
funcs.append(make_func())

View File

@@ -4,7 +4,12 @@ B027 - on lines 13, 16, 19, 23
"""
import abc
from abc import ABC
from abc import abstractmethod, abstractproperty
from abc import (
abstractmethod,
abstractproperty,
abstractclassmethod,
abstractstaticmethod,
)
from abc import abstractmethod as notabstract
from abc import abstractproperty as notabstract_property
@@ -55,6 +60,22 @@ class AbstractClass(ABC):
def abstract_6(self):
...
@abstractclassmethod
def abstract_7(self):
pass
@abc.abstractclassmethod
def abstract_8(self):
...
@abstractstaticmethod
def abstract_9(self):
pass
@abc.abstractstaticmethod
def abstract_10(self):
...
def body_1(self):
print("foo")
...
@@ -99,3 +120,11 @@ class AbstractClass(ABC):
@abstractmethod
def empty_1(self, foo: Union[str, int, list, float]):
...
from dataclasses import dataclass
@dataclass
class Foo(ABC): # noqa: B024
...

View File

@@ -0,0 +1,11 @@
import warnings
"""
Should emit:
B028 - on lines 8 and 9
"""
warnings.warn(DeprecationWarning("test"))
warnings.warn(DeprecationWarning("test"), source=None)
warnings.warn(DeprecationWarning("test"), source=None, stacklevel=2)
warnings.warn(DeprecationWarning("test"), stacklevel=1)

View File

@@ -0,0 +1,78 @@
"""
Should emit:
B030:
- line 12, column 8
- line 17, column 9
- line 22, column 21
- line 27, column 37
"""
try:
pass
except 1: # error
pass
try:
pass
except (1, ValueError): # error
pass
try:
pass
except (ValueError, (RuntimeError, (KeyError, TypeError))): # error
pass
try:
pass
except (ValueError, *(RuntimeError, (KeyError, TypeError))): # error
pass
try:
pass
except (*a, *(RuntimeError, (KeyError, TypeError))): # error
pass
try:
pass
except (ValueError, *(RuntimeError, TypeError)): # ok
pass
try:
pass
except (ValueError, *[RuntimeError, *(TypeError,)]): # ok
pass
try:
pass
except (*a, *b): # ok
pass
try:
pass
except (*a, *(RuntimeError, TypeError)): # ok
pass
try:
pass
except (*a, *(b, c)): # ok
pass
try:
pass
except (*a, *(*b, *c)): # ok
pass
def what_to_catch():
return ...
try:
pass
except what_to_catch(): # ok
pass

View File

@@ -0,0 +1,187 @@
import itertools
from itertools import groupby
shoppers = ["Jane", "Joe", "Sarah"]
items = [
("lettuce", "greens"),
("tomatoes", "greens"),
("cucumber", "greens"),
("chicken breast", "meats & fish"),
("salmon", "meats & fish"),
("ice cream", "frozen items"),
]
carts = {shopper: [] for shopper in shoppers}
def collect_shop_items(shopper, items):
# Imagine this an expensive database query or calculation that is
# advantageous to batch.
carts[shopper] += items
# Invoking the `groupby` function directly
for _section, section_items in groupby(items, key=lambda p: p[1]):
for shopper in shoppers:
shopper = shopper.title()
collect_shop_items(shopper, section_items) # B031
# We're outside the nested loop and used the group again.
collect_shop_items(shopper, section_items) # B031
for _section, section_items in groupby(items, key=lambda p: p[1]):
collect_shop_items("Jane", section_items)
collect_shop_items("Joe", section_items) # B031
# Make sure to detect in other loop constructs as well - `while` loop
for _section, section_items in groupby(items, key=lambda p: p[1]):
countdown = 3
while countdown > 0:
collect_shop_items(shopper, section_items) # B031
countdown -= 1
# Make sure to detect in other loop constructs as well - `list` comprehension
collection = []
for _section, section_items in groupby(items, key=lambda p: p[1]):
collection.append([list(section_items) for _ in range(3)]) # B031
unique_items = set()
another_set = set()
for _section, section_items in groupby(items, key=lambda p: p[1]):
# For nested loops, it should not flag the usage of the name
for item in section_items:
unique_items.add(item)
# But it should be detected when used again
for item in section_items: # B031
another_set.add(item)
for _section, section_items in groupby(items, key=lambda p: p[1]):
# Variable has been overridden, skip checking
section_items = list(unique_items)
collect_shop_items("Jane", section_items)
collect_shop_items("Jane", section_items)
for _section, section_items in groupby(items, key=lambda p: p[1]):
# Variable has been overridden, skip checking
# Not a realistic situation, just for testing purpose
(section_items := list(unique_items))
collect_shop_items("Jane", section_items)
collect_shop_items("Jane", section_items)
for _section, section_items in groupby(items, key=lambda p: p[1]):
# This is ok
collect_shop_items("Jane", section_items)
# Invocation via the `itertools` module
for _section, section_items in itertools.groupby(items, key=lambda p: p[1]):
for shopper in shoppers:
collect_shop_items(shopper, section_items) # B031
for _section, section_items in itertools.groupby(items, key=lambda p: p[1]):
_ = [collect_shop_items(shopper, section_items) for shopper in shoppers] # B031
for _section, section_items in itertools.groupby(items, key=lambda p: p[1]):
# The variable is overridden, skip checking.
_ = [_ for section_items in range(3)]
_ = [collect_shop_items(shopper, section_items) for shopper in shoppers]
for _section, section_items in itertools.groupby(items, key=lambda p: p[1]):
_ = [item for item in section_items]
for _section, section_items in itertools.groupby(items, key=lambda p: p[1]):
# The iterator is being used for the second time.
_ = [(item1, item2) for item1 in section_items for item2 in section_items] # B031
for _section, section_items in itertools.groupby(items, key=lambda p: p[1]):
if _section == "greens":
collect_shop_items(shopper, section_items)
else:
collect_shop_items(shopper, section_items)
collect_shop_items(shopper, section_items) # B031
for _section, section_items in itertools.groupby(items, key=lambda p: p[1]):
# Mutually exclusive branches shouldn't trigger the warning
if _section == "greens":
collect_shop_items(shopper, section_items)
if _section == "greens":
collect_shop_items(shopper, section_items) # B031
elif _section == "frozen items":
collect_shop_items(shopper, section_items) # B031
else:
collect_shop_items(shopper, section_items) # B031
collect_shop_items(shopper, section_items) # B031
elif _section == "frozen items":
# Mix `match` and `if` statements
match shopper:
case "Jane":
collect_shop_items(shopper, section_items)
if _section == "fourth":
collect_shop_items(shopper, section_items) # B031
case _:
collect_shop_items(shopper, section_items)
else:
collect_shop_items(shopper, section_items)
# Now, it should detect
collect_shop_items(shopper, section_items) # B031
for _section, section_items in itertools.groupby(items, key=lambda p: p[1]):
# Mutually exclusive branches shouldn't trigger the warning
match _section:
case "greens":
collect_shop_items(shopper, section_items)
match shopper:
case "Jane":
collect_shop_items(shopper, section_items) # B031
case _:
collect_shop_items(shopper, section_items) # B031
case "frozen items":
collect_shop_items(shopper, section_items)
collect_shop_items(shopper, section_items) # B031
case _:
collect_shop_items(shopper, section_items)
# Now, it should detect
collect_shop_items(shopper, section_items) # B031
for group in groupby(items, key=lambda p: p[1]):
# This is bad, but not detected currently
collect_shop_items("Jane", group[1])
collect_shop_items("Joe", group[1])
# https://github.com/astral-sh/ruff/issues/4050
for _section, section_items in itertools.groupby(items, key=lambda p: p[1]):
if _section == "greens":
for item in section_items:
collect_shop_items(shopper, item)
elif _section == "frozen items":
_ = [item for item in section_items]
else:
collect_shop_items(shopper, section_items)
# Make sure we ignore - but don't fail on more complicated invocations
for _key, (_value1, _value2) in groupby(
[("a", (1, 2)), ("b", (3, 4)), ("a", (5, 6))], key=lambda p: p[1]
):
collect_shop_items("Jane", group[1])
collect_shop_items("Joe", group[1])
# Make sure we ignore - but don't fail on more complicated invocations
for (_key1, _key2), (_value1, _value2) in groupby(
[(("a", "a"), (1, 2)), (("b", "b"), (3, 4)), (("a", "a"), (5, 6))],
key=lambda p: p[1],
):
collect_shop_items("Jane", group[1])
collect_shop_items("Joe", group[1])
# Let's redefine the `groupby` function to make sure we pick up the correct one.
# NOTE: This should always be at the end of the file.
def groupby(data, key=None):
pass
for name, group in groupby(items):
collect_shop_items("Jane", items)
# This shouldn't be flagged as the `groupby` function is different
collect_shop_items("Joe", items)

View File

@@ -0,0 +1,11 @@
###
# Errors.
###
incorrect_set = {"value1", 23, 5, "value1"}
incorrect_set = {1, 1}
###
# Non-errors.
###
correct_set = {"value1", 23, 5}
correct_set = {5, "5"}

View File

@@ -1,3 +1,6 @@
from itertools import count, cycle, repeat
# Errors
zip()
zip(range(3))
zip("a", "b")
@@ -5,6 +8,18 @@ zip("a", "b", *zip("c"))
zip(zip("a"), strict=False)
zip(zip("a", strict=True))
# OK
zip(range(3), strict=True)
zip("a", "b", strict=False)
zip("a", "b", "c", strict=True)
# OK (infinite iterators).
zip([1, 2, 3], cycle("ABCDEF"))
zip([1, 2, 3], count())
zip([1, 2, 3], repeat(1))
zip([1, 2, 3], repeat(1, None))
zip([1, 2, 3], repeat(1, times=None))
# Errors (limited iterators).
zip([1, 2, 3], repeat(1, 1))
zip([1, 2, 3], repeat(1, times=4))

View File

@@ -1,6 +1,6 @@
class MyClass:
ImportError = 4
id = 5
id: int
dir = "/"
def __init__(self):
@@ -10,3 +10,10 @@ class MyClass:
def str(self):
pass
from typing import TypedDict
class MyClass(TypedDict):
id: int

View File

@@ -631,3 +631,11 @@ result = function(
the_first_one = next(
(i for i in range(10) if i // 2 == 0) # COM812 fix should include the final bracket
)
foo = namedtuple(
name="foo",
status="bar",
message="sfdsdfsdgs fsdfsdf output!dsfdfsdjkg ghfskdjghkdssd sd fsdf s\n"[
:20
],
)

View File

@@ -1,13 +1,20 @@
x = set(x for x in range(3))
x = set(
x for x in range(3)
)
y = f'{set(a if a < 6 else 0 for a in range(3))}'
_ = '{}'.format(set(a if a < 6 else 0 for a in range(3)))
print(f'Hello {set(a for a in range(3))} World')
def set(*args, **kwargs):
return None
x = set(x for x in range(3))
y = f"{set(a if a < 6 else 0 for a in range(3))}"
_ = "{}".format(set(a if a < 6 else 0 for a in range(3)))
print(f"Hello {set(a for a in range(3))} World")
set(x for x in range(3))
def f(x):
return x
print(f'Hello {set(a for a in "abc")} World')
print(f"Hello {set(a for a in 'abc')} World")
print(f"Hello {set(f(a) for a in 'abc')} World")
print(f"{set(a for a in 'abc') - set(a for a in 'ab')}")
print(f"{ set(a for a in 'abc') - set(a for a in 'ab') }")
# The fix generated for this diagnostic is incorrect, as we add additional space
# around the set comprehension.
print(f"{ {set(a for a in 'abc')} }")

View File

@@ -5,3 +5,14 @@ dict(
dict(((x, x) for x in range(3)), z=3)
y = f'{dict((x, x) for x in range(3))}'
print(f'Hello {dict((x, x) for x in range(3))} World')
print(f"Hello {dict((x, x) for x in 'abc')} World")
print(f'Hello {dict((x, x) for x in "abc")} World')
print(f'Hello {dict((x,x) for x in "abc")} World')
f'{dict((x, x) for x in range(3)) | dict((x, x) for x in range(3))}'
f'{ dict((x, x) for x in range(3)) | dict((x, x) for x in range(3)) }'
def f(x):
return x
print(f'Hello {dict((x,f(x)) for x in "abc")} World')

View File

@@ -2,3 +2,14 @@ s = set([x for x in range(3)])
s = set(
[x for x in range(3)]
)
s = f"{set([x for x in 'ab'])}"
s = f'{set([x for x in "ab"])}'
def f(x):
return x
s = f"{set([f(x) for x in 'ab'])}"
s = f"{ set([x for x in 'ab']) | set([x for x in 'ab']) }"
s = f"{set([x for x in 'ab']) | set([x for x in 'ab'])}"

View File

@@ -1,2 +1,13 @@
dict([(i, i) for i in range(3)])
dict([(i, i) for i in range(3)], z=4)
def f(x):
return x
f'{dict([(s,s) for s in "ab"])}'
f"{dict([(s,s) for s in 'ab'])}"
f"{dict([(s, s) for s in 'ab'])}"
f"{dict([(s,f(s)) for s in 'ab'])}"
f'{dict([(s,s) for s in "ab"]) | dict([(s,s) for s in "ab"])}'
f'{ dict([(s,s) for s in "ab"]) | dict([(s,s) for s in "ab"]) }'

View File

@@ -16,3 +16,11 @@ set(
set(
[1,]
)
f"{set([1,2,3])}"
f"{set(['a', 'b'])}"
f'{set(["a", "b"])}'
f"{set(['a', 'b']) - set(['a'])}"
f"{ set(['a', 'b']) - set(['a']) }"
f"a {set(['a', 'b']) - set(['a'])} b"
f"a { set(['a', 'b']) - set(['a']) } b"

View File

@@ -10,3 +10,13 @@ def list():
a = list()
f"{dict(x='y')}"
f'{dict(x="y")}'
f"{dict()}"
f"a {dict()} b"
f"{dict(x='y') | dict(y='z')}"
f"{ dict(x='y') | dict(y='z') }"
f"a {dict(x='y') | dict(y='z')} b"
f"a { dict(x='y') | dict(y='z') } b"

View File

@@ -7,11 +7,14 @@ set(set(x))
set(list(x))
set(tuple(x))
set(sorted(x))
set(sorted(x, key=lambda y: y))
set(reversed(x))
sorted(list(x))
sorted(tuple(x))
sorted(sorted(x))
sorted(sorted(x, key=lambda y: y))
sorted(reversed(x))
sorted(list(x), key=lambda y: y)
tuple(
list(
[x, 3, "hell"\

View File

@@ -1,6 +1,19 @@
x = [1, 2, 3]
y = [("a", 1), ("b", 2), ("c", 3)]
z = [(1,), (2,), (3,)]
d = {"a": 1, "b": 2, "c": 3}
[i for i in x]
{i for i in x}
{k: v for k, v in y}
{k: v for k, v in d.items()}
[i for i, in z]
[i for i, j in y]
[i for i in x if i > 1]
[i for i in x for j in x]
{v: k for k, v in y}
{k.foo: k for k in y}
{k["foo"]: k for k in y}
{k: v if v else None for k, v in y}

View File

@@ -0,0 +1,10 @@
dict({})
dict({'a': 1})
dict({'x': 1 for x in range(10)})
dict(
{'x': 1 for x in range(10)}
)
dict({}, a=1)
dict({x: 1 for x in range(1)}, a=1)

View File

@@ -0,0 +1,39 @@
any([x.id for x in bar])
all([x.id for x in bar])
any( # first comment
[x.id for x in bar], # second comment
) # third comment
all( # first comment
[x.id for x in bar], # second comment
) # third comment
any({x.id for x in bar})
# OK
all(x.id for x in bar)
all(x.id for x in bar)
any(x.id for x in bar)
all((x.id for x in bar))
async def f() -> bool:
return all([await use_greeting(greeting) for greeting in await greetings()])
# Special comment handling
any(
[ # lbracket comment
# second line comment
i.bit_count()
# random middle comment
for i in range(5) # rbracket comment
] # rpar comment
# trailing comment
)
# Weird case where the function call, opening bracket, and comment are all
# on the same line.
any([ # lbracket comment
# second line comment
i.bit_count() for i in range(5) # rbracket comment
] # rpar comment
)

View File

@@ -0,0 +1,113 @@
from django.db import models
from django.db.models import Model
class StrBeforeRandomField(models.Model):
"""Model with `__str__` before a random property."""
class Meta:
verbose_name = "test"
verbose_name_plural = "tests"
def __str__(self):
return ""
random_property = "foo"
class StrBeforeFieldModel(models.Model):
"""Model with `__str__` before fields."""
class Meta:
verbose_name = "test"
verbose_name_plural = "tests"
def __str__(self):
return "foobar"
first_name = models.CharField(max_length=32)
class ManagerBeforeField(models.Model):
"""Model with manager before fields."""
objects = "manager"
class Meta:
verbose_name = "test"
verbose_name_plural = "tests"
def __str__(self):
return "foobar"
first_name = models.CharField(max_length=32)
class CustomMethodBeforeStr(models.Model):
"""Model with a custom method before `__str__`."""
class Meta:
verbose_name = "test"
verbose_name_plural = "tests"
def my_method(self):
pass
def __str__(self):
return "foobar"
class GetAbsoluteUrlBeforeSave(Model):
"""Model with `get_absolute_url` method before `save` method.
Subclass this directly using the `Model` class.
"""
def get_absolute_url(self):
pass
def save(self):
pass
class ConstantsAreNotFields(models.Model):
"""Model with an assignment to a constant after `__str__`."""
first_name = models.CharField(max_length=32)
class Meta:
verbose_name = "test"
verbose_name_plural = "tests"
def __str__(self):
pass
MY_CONSTANT = id(1)
class PerfectlyFine(models.Model):
"""Model which has everything in perfect order."""
first_name = models.CharField(max_length=32)
last_name = models.CharField(max_length=32)
objects = "manager"
class Meta:
verbose_name = "test"
verbose_name_plural = "tests"
def __str__(self):
return "Perfectly fine!"
def save(self, **kwargs):
super(PerfectlyFine, self).save(**kwargs)
def get_absolute_url(self):
return "http://%s" % self
def my_method(self):
pass
@property
def random_property(self):
return "%s" % self

View File

@@ -9,6 +9,10 @@ def f_a_short():
raise RuntimeError("Error")
def f_a_empty():
raise RuntimeError("")
def f_b():
example = "example"
raise RuntimeError(f"This is an {example} exception")
@@ -21,3 +25,36 @@ def f_c():
def f_ok():
msg = "hello"
raise RuntimeError(msg)
def f_unfixable():
msg = "hello"
raise RuntimeError("This is an example exception")
def f_msg_in_nested_scope():
def nested():
msg = "hello"
raise RuntimeError("This is an example exception")
def f_msg_in_parent_scope():
msg = "hello"
def nested():
raise RuntimeError("This is an example exception")
def f_fix_indentation_check(foo):
if foo:
raise RuntimeError("This is an example exception")
else:
if foo == "foo":
raise RuntimeError(f"This is an exception: {foo}")
raise RuntimeError("This is an exception: {}".format(foo))
# Report these, but don't fix them
if foo: raise RuntimeError("This is an example exception")
if foo: x = 1; raise RuntimeError("This is an example exception")

View File

@@ -0,0 +1,8 @@
# TODO: todo
# todo: todo
# XXX: xxx
# xxx: xxx
# HACK: hack
# hack: hack
# FIXME: fixme
# fixme: fixme

View File

@@ -0,0 +1,7 @@
from typing import List
import typing as t
def main(_: List[int]) -> None:
a_list: t.List[str] = []
a_list.append("hello")

View File

@@ -0,0 +1,6 @@
from typing import List
def main() -> None:
a_list: List[str] = []
a_list.append("hello")

View File

@@ -0,0 +1,8 @@
from typing import Dict, List, Optional, Set, Union, cast
def main() -> None:
a_list: List[Optional[str]] = []
a_list.append("hello")
a_dict = cast(Dict[int | None, Union[int, Set[bool]]], {})
a_dict[1] = {True, False}

View File

@@ -0,0 +1,6 @@
import typing
def main() -> None:
a_list: typing.List[str] = []
a_list.append("hello")

View File

@@ -0,0 +1,6 @@
import typing as t
def main() -> None:
a_list: t.List[str] = []
a_list.append("hello")

View File

@@ -0,0 +1,7 @@
def main() -> None:
a_list: list[str] = []
a_list.append("hello")
def hello(y: dict[str, int]) -> None:
del y

View File

@@ -0,0 +1,7 @@
def main() -> None:
a_list: list[str] | None = []
a_list.append("hello")
def hello(y: dict[str, int] | None) -> None:
del y

View File

@@ -0,0 +1,8 @@
def main() -> None:
a_list: list[str | None] = []
a_list.append("hello")
def hello(y: dict[str | None, int]) -> None:
z: tuple[str, str | None, str] = tuple(y)
del z

View File

@@ -0,0 +1,3 @@
def main() -> str:
a_str = "hello"
return a_str

View File

@@ -0,0 +1,10 @@
from typing import NamedTuple
class Stuff(NamedTuple):
x: int
def main() -> None:
a_list = Stuff(5)
print(a_list)

View File

@@ -0,0 +1,6 @@
from __future__ import annotations
def main() -> None:
a_list: list[str] = []
a_list.append("hello")

View File

@@ -0,0 +1,8 @@
import typing
IRRELEVANT = typing.TypeVar
def main() -> None:
List: list[str] = []
List.append("hello")

View File

@@ -0,0 +1 @@
_(f"{'value'}")

View File

@@ -0,0 +1 @@
_("{}".format("line"))

View File

@@ -0,0 +1 @@
_("%s" % "line")

View File

@@ -34,3 +34,19 @@ _ = (
b"abc"
b"def"
)
_ = """a""" """b"""
_ = """a
b""" """c
d"""
_ = f"""a""" f"""b"""
_ = f"a" "b"
_ = """a""" "b"
_ = 'a' "b"
_ = rf"a" rf"b"

View File

@@ -0,0 +1,16 @@
import typing as t # banned
import typing as ty # banned
import numpy as nmp # banned
import numpy as npy # banned
import tensorflow.keras.backend as K # banned
import torch.nn.functional as F # banned
from tensorflow.keras import backend as K # banned
from torch.nn import functional as F # banned
from typing import Any # ok
import numpy as np # ok
import tensorflow as tf # ok
import torch.nn as nn # ok
from tensorflow.keras import backend # ok

View File

@@ -0,0 +1,10 @@
from logging.config import BaseConfigurator # banned
from typing import Any, Dict # banned
from typing import * # banned
from pandas import DataFrame # banned
from pandas import * # banned
import logging.config # ok
import typing # ok
import pandas # ok

View File

@@ -1,3 +1,18 @@
import logging
import logging as foo
logging.info("Hello {}".format("World!"))
logging.log(logging.INFO, "Hello {}".format("World!"))
foo.info("Hello {}".format("World!"))
logging.log(logging.INFO, msg="Hello {}".format("World!"))
logging.log(level=logging.INFO, msg="Hello {}".format("World!"))
logging.log(msg="Hello {}".format("World!"), level=logging.INFO)
# Flask support
import flask
from flask import current_app
from flask import current_app as app
flask.current_app.logger.info("Hello {}".format("World!"))
current_app.logger.info("Hello {}".format("World!"))
app.logger.log(logging.INFO, "Hello {}".format("World!"))

View File

@@ -1,3 +1,4 @@
import logging
logging.info("Hello %s" % "World!")
logging.log(logging.INFO, "Hello %s" % "World!")

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