Commit Graph

4501 Commits

Author SHA1 Message Date
Carl Meyer fcaa62f0d9
[red-knot] support if-expressions in type inference and CFG (#11765) 2024-06-06 04:40:44 -06:00
Embers-of-the-Fire f144edeefa
[Bug fix] Fix rule B909's panic when checking large loop blocks (#11772) 2024-06-06 12:23:28 +02:00
Dhruv Manilawala 6c1fa1d440
Use speculative parsing for with-items (#11770)
## Summary

This PR updates the with-items parsing logic to use speculative parsing
instead.

### Existing logic

First, let's understand the previous logic:
1. The parser sees `(`, it doesn't know whether it's part of a
parenthesized with items or a parenthesized expression
2. Consider it a parenthesized with items and perform a hand-rolled
speculative parsing
3. Then, verify the assumption and if it's incorrect convert the parsed
with items into an appropriate expression which becomes part of the
first with item

Here, in (3) there are lots of edge cases which we've to deal with:
1. Trailing comma with a single element should be [converted to the
expression as
is](9b2cf569b2/crates/ruff_python_parser/src/parser/statement.rs (L2140-L2153))
2. Trailing comma with multiple elements should be [converted to a tuple
expression](9b2cf569b2/crates/ruff_python_parser/src/parser/statement.rs (L2155-L2178))
3. Limit the allowed expression based on whether it's
[(1)](9b2cf569b2/crates/ruff_python_parser/src/parser/statement.rs (L2144-L2152))
or
[(2)](9b2cf569b2/crates/ruff_python_parser/src/parser/statement.rs (L2157-L2171))
4. [Consider postfix
expressions](9b2cf569b2/crates/ruff_python_parser/src/parser/statement.rs (L2181-L2200))
after (3)
5. [Consider `if`
expressions](9b2cf569b2/crates/ruff_python_parser/src/parser/statement.rs (L2203-L2208))
after (3)
6. [Consider binary
expressions](9b2cf569b2/crates/ruff_python_parser/src/parser/statement.rs (L2210-L2228))
after (3)

Consider other cases like
* [Single generator
expression](9b2cf569b2/crates/ruff_python_parser/src/parser/statement.rs (L2020-L2035))
* [Expecting a
comma](9b2cf569b2/crates/ruff_python_parser/src/parser/statement.rs (L2122-L2130))

And, this is all possible only if we allow parsing these expressions in
the [with item parsing
logic](9b2cf569b2/crates/ruff_python_parser/src/parser/statement.rs (L2287-L2334)).

### Speculative parsing

With #11457 merged, we can simplify this logic by changing the step (3)
from above to just rewind the parser back to the `(` if our assumption
(parenthesized with-items) was incorrect and then continue parsing it
considering parenthesized expression.

This also behaves a lot similar to what a PEG parser does which is to
consider the first grammar rule and if it fails consider the second
grammar rule and so on.

resolves: #11639 

## Test Plan

- [x] Verify the updated snapshots
- [x] Run the fuzzer on around 3000 valid source code (locally)
2024-06-06 08:59:56 +00:00
Max Muoto 5a5a588a72
[`pylint`] Implement `dict-iter-missing-items` (`C0206`) (#11688)
## Summary

<!-- What's the purpose of the change? What does it do, and why? -->

This PR implements the [consider dict
items](https://pylint.pycqa.org/en/latest/user_guide/messages/convention/consider-using-dict-items.html)
rule from Pylint. Enabling this rule flags:

```python
ORCHESTRA = {
    "violin": "strings",
    "oboe": "woodwind",
    "tuba": "brass",
    "gong": "percussion",
}


for instrument in ORCHESTRA: 
    print(f"{instrument}: {ORCHESTRA[instrument]}")

for instrument in ORCHESTRA.keys(): 
    print(f"{instrument}: {ORCHESTRA[instrument]}")

for instrument in (inline_dict := {"foo": "bar"}): 
    print(f"{instrument}: {inline_dict[instrument]}")
```

For not using `items()` to extract the value out of the dict. We ignore
the case of an assignment, as you can't modify the underlying
representation with the value in the list of tuples returned.
 

## Test Plan

<!-- How was it tested? -->

`cargo test`.

---------

Co-authored-by: Charlie Marsh <charlie.r.marsh@gmail.com>
2024-06-06 00:28:01 -04:00
Carl Meyer 084e5464fb
[red-knot] support walrus expressions in type inference (#11762)
## Summary

Add support for walrus expressions, both in expression type inference
and in symbol definition type inference.

## Test Plan

Added test.
2024-06-05 15:13:10 -06:00
Carl Meyer 31f97329c0
[red-knot] refactor Definitions out of symbol table (#11761)
## Summary

Definitions are used in symbol table and in flow graph, and aren't
inherently owned by one or the other; move them into their own
submodule.

## Test Plan

Existing tests.
2024-06-05 14:35:01 -06:00
Carl Meyer b46e9e825a
[red-knot] arithmetic on int literals (#11760)
## Summary

Add support for inferring int literal types from basic arithmetic on int
literals. Just to begin showing examples of resolving more complex
expression types, and because this will be useful in testing walrus
expressions.

## Test Plan

Added test.
2024-06-05 14:10:37 -06:00
Carl Meyer 9b2cf569b2
[red-knot] rename Definition::None to Definition::Unbound (#11758)
## Summary

After looking at this a bit, I think it does make sense to have
`Unbound` as part of the `Definition` enum; if we are modeling `Unbound`
as a type (which currently we are), then every symbol implicitly starts
each scope with a "definition" as unbound, and the cleanest way to model
that is as a real `Definition`. We should be able to handle a definition
of "unbound" anywhere we handle definitions.

But the name `None` wasn't clear enough; changing the name to `Unbound`
and adding a doc comment.

Also change `[first].into_iter()` to `std::iter::once(first)`, from
post-land code review on a prior PR.

## Test Plan

Existing tests.
2024-06-05 11:32:26 -06:00
Micha Reiser 5806bc915d
Fix formatter instability for lines only consisting of zero-width characters (#11748) 2024-06-05 17:55:14 +02:00
Micha Reiser b0b4706e2d
Red-knot: Track scopes per expression (#11754) 2024-06-05 17:53:26 +02:00
Dhruv Manilawala a8cf7096ff
Bump version to v0.4.8 (#11755)
Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
2024-06-05 20:51:31 +05:30
Carl Meyer 895eb3ef48
[red-knot] refactor CFG outside of symbol table (#11746) 2024-06-05 06:23:43 -06:00
Dhruv Manilawala 2e0a9755e0
Disallow access to `Parsed` output, use the API instead (#11741)
## Summary

This PR is a follow-up to #11740 to restrict access to the `Parsed`
output by replacing the `parsed` API function with a more specific one.
Currently, that is `comment_ranges` but the linked PR exposes a `tokens`
method.

The main motivation is so that there's no way to get an incorrect
information from the checker. And, it also encapsulates the source of
the comment ranges and the tokens itself. This way it would become
easier to just update the checker if the source for these information
changes in the future.

## Test Plan

`cargo insta test`
2024-06-05 08:24:19 +00:00
Dhruv Manilawala b021b5babe
Use `Tokens` from parsed type annotation or parsed source (#11740)
## Summary

This PR fixes a bug where the checker would require the tokens for an
invalid offset w.r.t. the source code.

Taking the source code from the linked issue as an example:
```py
relese_version :"0.0is 64"
```

Now, this isn't really a valid type annotation but that's what this PR
is fixing. Regardless of whether it's valid or not, Ruff shouldn't
panic.

The checker would visit the parsed type annotation (`0.0is 64`) and try
to detect any violations. Certain rule logic requests the tokens for the
same but it would fail because the lexer would only have the `String`
token considering original source code. This worked before because the
lexer was invoked again for each rule logic.

The solution is to store the parsed type annotation on the checker if
it's in a typing context and use the tokens from that instead if it's
available. This is enforced by creating a new API on the checker to get
the tokens.

But, this means that there are two ways to get the tokens via the
checker API. I want to restrict this in a follow-up PR (#11741) to only
expose `tokens` and `comment_ranges` as methods and restrict access to
the parsed source code.

fixes: #11736 

## Test Plan

- [x] Add a test case for `F632` rule and update the snapshot
- [x] Check all affected rules
- [x] No ecosystem changes
2024-06-05 07:50:33 +00:00
Dhruv Manilawala eed6d784df
Update type annotation parsing API to return `Parsed` (#11739)
## Summary

This PR updates the return type of `parse_type_annotation` from `Expr`
to `Parsed<ModExpression>`. This is to allow accessing the tokens for
the parsed sub-expression in the follow-up PR.

## Test Plan

`cargo insta test`
2024-06-05 12:59:43 +05:30
Jane Lewis 8338db6c12
`ruff server`: Formatting a document with syntax problems no longer spams a visible error popup (#11745)
## Summary

Fixes https://github.com/astral-sh/ruff-vscode/issues/482.

I've made adjustments to `format` and `format_range` that handle parsing
errors before they become server errors. We'll still log this as a
problem, but there will no longer be a visible popup.

## Test Plan

Instead of seeing a visible error when formatting a document with syntax
issues, you should see this warning in the LSP logs:

<img width="991" alt="Screenshot 2024-06-04 at 3 38 23 PM"
src="https://github.com/astral-sh/ruff/assets/19577865/9d68947d-6462-4ca6-ab5a-65e573c91db6">

Similarly, if you try to format a range with syntax issues, you should
see this warning in the LSP logs instead of a visible error popup:

<img width="1010" alt="Screenshot 2024-06-04 at 3 39 10 PM"
src="https://github.com/astral-sh/ruff/assets/19577865/99fff098-798d-406a-976e-81ead0da0352">

---------

Co-authored-by: Zanie Blue <contact@zanie.dev>
2024-06-04 17:18:21 -07:00
Carl Meyer d056d09547
[red-knot] add if-statement support to FlowGraph (#11673)
## Summary

Add if-statement support to FlowGraph. This introduces branches and
joins in the graph for the first time.

## Test Plan

Added tests.
2024-06-04 15:09:39 -06:00
Mateusz Sokół 1645be018d
Update `NPY001` rule for NumPy 2.0 (#11735)
Hi!

This PR addresses https://github.com/astral-sh/ruff/issues/11093.

It skips `np.bool` and `np.long` replacements as both of these names
were reintroduced in NumPy 2.0 with a different meaning
(https://github.com/numpy/numpy/pull/24922,
https://github.com/numpy/numpy/pull/25080).
With this change `NPY001` will no longer conflict with `NPY201`. For
projects using NumPy 1.x `np.bool` and `np.long` has been deprecated and
removed long time ago, and accessing them yields an informative error
message.
2024-06-04 19:23:42 +00:00
Dhruv Manilawala 2567e14b7a
Lexer should consider BOM for the start offset (#11732)
## Summary

This PR fixes a bug where the lexer didn't consider the BOM into the
start offset.

fixes: #11731

## Test Plan

Add multiple test cases which involves BOM character in the source for
the lexer and verify the snapshot.
2024-06-04 08:45:46 +00:00
Dhruv Manilawala 3b19df04d7
Use cursor offset for lexer checkpoint (#11734)
## Summary

This PR updates the lexer checkpoint to store the cursor offset instead
of cloning the cursor itself. This reduces the size of `LexerCheckpoint`
from 136 to 112 bytes and also removes the need for lifetime.

## Test Plan

`cargo insta test`
2024-06-04 14:13:57 +05:30
Micha Reiser 6ffb96171a
red-knot: Change `resolve_global_symbol` to take `Module` as an argument (#11723) 2024-06-04 06:20:50 +00:00
Micha Reiser 64165bee43
red-knot: Use `parse_unchecked` to get all parse errors (#11725) 2024-06-04 06:04:48 +00:00
Charlie Marsh 0c75548146
Respect per-file ignores for blanket and redirected noqa rules (#11728)
## Summary

Ensures that we respect per-file ignores and exemptions for these rules.
Specifically, we allow:

```python
# ruff: noqa: PGH004
```

...to ignore `PGH004`.
2024-06-04 03:57:59 +00:00
Alex b56a577f25
[`pygrep_hooks`] Check blanket ignores via file-level pragmas (`PGH004`) (#11540)
## Summary

Should resolve https://github.com/astral-sh/ruff/issues/11454.

This is my first PR to `ruff`, so I may have missed something.

If I understood the suggestion in the issue correctly, rule `PGH004`
should be set to `Preview` again.

## Test Plan

Created two fixtures derived from the issue.
2024-06-04 03:42:58 +00:00
Tushar Sadhwani e1133a24ed
[`flake8-pyi`] Implement `PYI063` (#11699)
## Summary
Implements `Y063` from `flake8-pyi`.

## Test Plan
`cargo test` / `cargo insta review`
2024-06-04 03:15:04 +00:00
Charlie Marsh 2f8ac1e9b3
Fix `red-knot` compilation (#11727)
## Summary

Perhaps a result of a bad rebase, but `cargo clippy --fix --workspace
--all-targets -- -D warnings` does not pass on main as-is.
2024-06-04 03:03:38 +00:00
Carl Meyer 3fb2028506
[red-knot] extract helper functions in inference tests (#11671)
There's a lot of repeat boilerplate in the type inference tests; this
cuts it down a lot.
2024-06-03 17:46:04 -06:00
Carl Meyer 3f9ee31efb
[red-knot] use reachable definitions in infer_expression_type (#11670)
## Summary

Switch name resolution in `infer_expression_type` from resolving the
public type of a symbol, to resolving the reachable definitions of that
symbol from the reference point, using the flow graph.

This surfaced a bug in the flow graph implementation and a bug in symbol
table building, both of which are also fixed here.

The bug in flow graph implementation was that when we pushed and popped
scopes, we didn't maintain a stack of "current flow nodes" in all
stacked scopes, to be restored when we returned to that scope. Now we
do.

The bug in symbol table building that we didn't visit the parts of
functions and class definitions in the correct scopes. E.g. decorators
should be visited in the outer scope, arguments should be visited inside
the type-params scope (if any) but not inside the function body scope,
and only the body itself should actually be visited inside the body
scope. Fixing this requires that we no longer use `walk_stmt` here,
instead we have to visit each individual component.

## Test Plan

Added test.
2024-06-03 17:45:31 -06:00
Carl Meyer b02d3f3fd9
[red-knot] infer_symbol_public_type infers union of all definitions (#11669)
## Summary

Rename `infer_symbol_type` to `infer_symbol_public_type`, and allow it
to work on symbols with more than one definition. For now, use the most
cautious/sound inference, which is the union of all definitions. We can
prune this union more in future by eliminating definitions if we can
show that they can't be visible (this requires both that the symbol is
definitely later reassigned, and that there is no intervening
call/import that might be able to see the over-written definition).

## Test Plan

Added a test showing inference of union from multiple definitions.
2024-06-03 17:27:06 -06:00
Dhruv Manilawala 2b28889ca9
Isolate non-breaking whitespace indentation test case (#11721)
As discussed in Discord, this moves the test case for non-breaking
whitespace into its own method.
2024-06-03 13:20:55 +00:00
Dhruv Manilawala 8db147c09d
Generator should add a newline before type statement (#11720)
## Summary

This PR fixes a bug where the `Generator` wouldn't add a newline before
a type alias statement. This is because it wasn't using the `statement`
macro which takes care of the newline.

Without this fix, a code like:
```py
type X = int
type Y = str
```

The generator would produce:
```py
type X = inttype Y = str
```

## Test Plan

Add a test case.
2024-06-03 18:44:21 +05:30
Dhruv Manilawala a58bde6958
Remove less used parser dependencies (#11718)
## Summary

This PR removes the following dependencies from the `ruff_python_parser`
crate:
* `anyhow` (moved to dev dependencies)
* `is-macro`
* `itertools`

The main motivation is that they aren't used much.

Additionally, it updates the return type of `parse_type_annotation` to
use a more specific `ParseError` instead of the generic `anyhow::Error`.

## Test Plan

`cargo insta test`
2024-06-03 13:08:24 +00:00
Dhruv Manilawala f4e23d2dff
Use string expression for parsing type annotation (#11717)
## Summary

This PR updates the logic for parsing type annotation to accept a
`ExprStringLiteral` node instead of the string value and the range.

The main motivation of this change is to simplify the implementation of
`parse_type_annotation` function with:
* Use the `opener_len` and `closer_len` from the string flags to get the
raw contents range instead of extracting it via
	* `str::leading_quote(expression).unwrap().text_len()`
	* `str::trailing_quote(expression).unwrap().text_len()`
* Avoid comparing the string content if we already know that it's
implicitly concatenated

## Test Plan

`cargo insta test`
2024-06-03 13:04:03 +00:00
Dhruv Manilawala 4a155e2b22
Re-order lexer methods (#11716)
## Summary

This PR re-orders the lexer methods in the following order:

1. `next_token`
2. `lex_token`
3. `eat_indentation`
4. `handle_indentation`
5. `skip_whitespace`
6. `consume_ascii_character`
7. `try_single_char_prefix`
8. `try_double_char_prefix`
9. `lex_identifier`
10. `lex_fstring_start`
11. `lex_fstring_middle_or_end`
12. `lex_string`
13. `lex_number`
14. `lex_number_radix`
15. `lex_decimal_number`
16. `radix_run`
17. `lex_comment`
18. `lex_ipython_escape_command`
19. `consume_end`

Following was considered for the ordering:
* 1 is the main entry point which delegates to 2
* 3, 4, 5 are all related to whitespace which is done first
* 6 is the entrypoint for an ascii character which delegates to 9, 12,
13, 17, 18, 19
* Others are grouped around similar kind of methods
2024-06-03 12:58:35 +00:00
Dhruv Manilawala bf5b62edac
Maintain synchronicity between the lexer and the parser (#11457)
## Summary

This PR updates the entire parser stack in multiple ways:

### Make the lexer lazy

* https://github.com/astral-sh/ruff/pull/11244
* https://github.com/astral-sh/ruff/pull/11473

Previously, Ruff's lexer would act as an iterator. The parser would
collect all the tokens in a vector first and then process the tokens to
create the syntax tree.

The first task in this project is to update the entire parsing flow to
make the lexer lazy. This includes the `Lexer`, `TokenSource`, and
`Parser`. For context, the `TokenSource` is a wrapper around the `Lexer`
to filter out the trivia tokens[^1]. Now, the parser will ask the token
source to get the next token and only then the lexer will continue and
emit the token. This means that the lexer needs to be aware of the
"current" token. When the `next_token` is called, the current token will
be updated with the newly lexed token.

The main motivation to make the lexer lazy is to allow re-lexing a token
in a different context. This is going to be really useful to make the
parser error resilience. For example, currently the emitted tokens
remains the same even if the parser can recover from an unclosed
parenthesis. This is important because the lexer emits a
`NonLogicalNewline` in parenthesized context while a normal `Newline` in
non-parenthesized context. This different kinds of newline is also used
to emit the indentation tokens which is important for the parser as it's
used to determine the start and end of a block.

Additionally, this allows us to implement the following functionalities:
1. Checkpoint - rewind infrastructure: The idea here is to create a
checkpoint and continue lexing. At a later point, this checkpoint can be
used to rewind the lexer back to the provided checkpoint.
2. Remove the `SoftKeywordTransformer` and instead use lookahead or
speculative parsing to determine whether a soft keyword is a keyword or
an identifier
3. Remove the `Tok` enum. The `Tok` enum represents the tokens emitted
by the lexer but it contains owned data which makes it expensive to
clone. The new `TokenKind` enum just represents the type of token which
is very cheap.

This brings up a question as to how will the parser get the owned value
which was stored on `Tok`. This will be solved by introducing a new
`TokenValue` enum which only contains a subset of token kinds which has
the owned value. This is stored on the lexer and is requested by the
parser when it wants to process the data. For example:
8196720f80/crates/ruff_python_parser/src/parser/expression.rs (L1260-L1262)

[^1]: Trivia tokens are `NonLogicalNewline` and `Comment`

### Remove `SoftKeywordTransformer`

* https://github.com/astral-sh/ruff/pull/11441
* https://github.com/astral-sh/ruff/pull/11459
* https://github.com/astral-sh/ruff/pull/11442
* https://github.com/astral-sh/ruff/pull/11443
* https://github.com/astral-sh/ruff/pull/11474

For context,
https://github.com/RustPython/RustPython/pull/4519/files#diff-5de40045e78e794aa5ab0b8aacf531aa477daf826d31ca129467703855408220
added support for soft keywords in the parser which uses infinite
lookahead to classify a soft keyword as a keyword or an identifier. This
is a brilliant idea as it basically wraps the existing Lexer and works
on top of it which means that the logic for lexing and re-lexing a soft
keyword remains separate. The change here is to remove
`SoftKeywordTransformer` and let the parser determine this based on
context, lookahead and speculative parsing.

* **Context:** The transformer needs to know the position of the lexer
between it being at a statement position or a simple statement position.
This is because a `match` token starts a compound statement while a
`type` token starts a simple statement. **The parser already knows
this.**
* **Lookahead:** Now that the parser knows the context it can perform
lookahead of up to two tokens to classify the soft keyword. The logic
for this is mentioned in the PR implementing it for `type` and `match
soft keyword.
* **Speculative parsing:** This is where the checkpoint - rewind
infrastructure helps. For `match` soft keyword, there are certain cases
for which we can't classify based on lookahead. The idea here is to
create a checkpoint and keep parsing. Based on whether the parsing was
successful and what tokens are ahead we can classify the remaining
cases. Refer to #11443 for more details.

If the soft keyword is being parsed in an identifier context, it'll be
converted to an identifier and the emitted token will be updated as
well. Refer
8196720f80/crates/ruff_python_parser/src/parser/expression.rs (L487-L491).

The `case` soft keyword doesn't require any special handling because
it'll be a keyword only in the context of a match statement.

### Update the parser API

* https://github.com/astral-sh/ruff/pull/11494
* https://github.com/astral-sh/ruff/pull/11505

Now that the lexer is in sync with the parser, and the parser helps to
determine whether a soft keyword is a keyword or an identifier, the
lexer cannot be used on its own. The reason being that it's not
sensitive to the context (which is correct). This means that the parser
API needs to be updated to not allow any access to the lexer.

Previously, there were multiple ways to parse the source code:
1. Passing the source code itself
2. Or, passing the tokens

Now that the lexer and parser are working together, the API
corresponding to (2) cannot exists. The final API is mentioned in this
PR description: https://github.com/astral-sh/ruff/pull/11494.

### Refactor the downstream tools (linter and formatter)

* https://github.com/astral-sh/ruff/pull/11511
* https://github.com/astral-sh/ruff/pull/11515
* https://github.com/astral-sh/ruff/pull/11529
* https://github.com/astral-sh/ruff/pull/11562
* https://github.com/astral-sh/ruff/pull/11592

And, the final set of changes involves updating all references of the
lexer and `Tok` enum. This was done in two-parts:
1. Update all the references in a way that doesn't require any changes
from this PR i.e., it can be done independently
	* https://github.com/astral-sh/ruff/pull/11402
	* https://github.com/astral-sh/ruff/pull/11406
	* https://github.com/astral-sh/ruff/pull/11418
	* https://github.com/astral-sh/ruff/pull/11419
	* https://github.com/astral-sh/ruff/pull/11420
	* https://github.com/astral-sh/ruff/pull/11424
2. Update all the remaining references to use the changes made in this
PR

For (2), there were various strategies used:
1. Introduce a new `Tokens` struct which wraps the token vector and add
methods to query a certain subset of tokens. These includes:
	1. `up_to_first_unknown` which replaces the `tokenize` function
2. `in_range` and `after` which replaces the `lex_starts_at` function
where the former returns the tokens within the given range while the
latter returns all the tokens after the given offset
2. Introduce a new `TokenFlags` which is a set of flags to query certain
information from a token. Currently, this information is only limited to
any string type token but can be expanded to include other information
in the future as needed. https://github.com/astral-sh/ruff/pull/11578
3. Move the `CommentRanges` to the parsed output because this
information is common to both the linter and the formatter. This removes
the need for `tokens_and_ranges` function.

## Test Plan

- [x] Update and verify the test snapshots
- [x] Make sure the entire test suite is passing
- [x] Make sure there are no changes in the ecosystem checks
- [x] Run the fuzzer on the parser
- [x] Run this change on dozens of open-source projects

### Running this change on dozens of open-source projects

Refer to the PR description to get the list of open source projects used
for testing.

Now, the following tests were done between `main` and this branch:
1. Compare the output of `--select=E999` (syntax errors)
2. Compare the output of default rule selection
3. Compare the output of `--select=ALL`

**Conclusion: all output were same**

## What's next?

The next step is to introduce re-lexing logic and update the parser to
feed the recovery information to the lexer so that it can emit the
correct token. This moves us one step closer to having error resilience
in the parser and provides Ruff the possibility to lint even if the
source code contains syntax errors.
2024-06-03 18:23:50 +05:30
Alex Waygood 94a3c53841
Update UP035 for Python 3.13 and the latest version of typing_extensions (#11693) 2024-06-02 22:59:48 +01:00
Tobias Fischer 0ea2519e80
Add RDJson support. (#11682)
## Summary

Implement support for RDJson output for `ruff check`, as requested in
#8655.

## Test Plan

Tested using a snapshot test. Same approach as for e.g. the JSON output
formatter.

## Additional info

I tried to keep the implementation close to the JSON implementation.

I had to deviate a bit to make the `suggestions` key work: If there are
no suggestions, then setting `suggestions` to `null` is invalid
according to the JSONSchema. Therefore, I opted for a slightly more
complex implementation, that skips the `suggestions` key entirely if
there are no fixes available for the given diagnostic. Maybe it would
have been easier to set `"suggestions": []`, but I ended up doing it
this way.

I didn't consider notebooks, as I _think_ that RDJson doesn't work with
notebooks. This should be confirmed, and if so, there should be some
form of warning or error emitted when trying to output diagnostics for a
notebook.

I also didn't consider `ruff format`, as this comment:
https://github.com/astral-sh/ruff/issues/8655#issuecomment-1811446160
suggests that that wouldn't be compatible.

I'm new to Rust, any feedback is appreciated. 🙂 I
implemented this in order to have a productive rainy saturday afternoon,
I'm not knowledgeable about RDJson beyond the sources linked in the
issue.
2024-06-02 17:59:57 +00:00
Charlie Marsh 6d79ddc0aa
[`pyupgrade`] Write empty string in lieu of panic (#11696)
## Summary

Closes https://github.com/astral-sh/ruff/issues/11692.
2024-06-02 17:51:03 +00:00
Alex Waygood 9f3e609278
Make tests aware that py313 is the latest supported Python version (#11690) 2024-06-02 13:06:04 +00:00
Charlie Marsh b36dd1aa51
[`flake8-simplify`] Simplify double negatives in `SIM103` (#11684)
## Summary

Closes: https://github.com/astral-sh/ruff/issues/11685.
2024-06-01 23:21:11 +00:00
github-actions[bot] 99834ee93d
Sync vendored typeshed stubs (#11668)
Close and reopen this PR to trigger CI

Co-authored-by: typeshedbot <>
2024-05-31 22:26:20 -06:00
Tobias Fischer 312f6640b8
[`flake8-bugbear`] Implement `return-in-generator` (`B901`) (#11644)
## Summary

This PR implements the rule B901, which is part of the opinionated rules
of `flake8-bugbear`.

This rule seems to be desired in `ruff` as per
https://github.com/astral-sh/ruff/issues/3758 and
https://github.com/astral-sh/ruff/issues/2954#issuecomment-1441162976.

## Test Plan

As this PR was made closely following the
[CONTRIBUTING.md](8a25531a71/CONTRIBUTING.md),
it tests using the snapshot approach, that is described there.

## Sources

The implementation is inspired by [the original implementation in the
`flake8-bugbear`
repository](d1aec4cbef/bugbear.py (L1092)).
The error message and [test
file](d1aec4cbef/tests/b901.py)
where also copied from there.

The documentation I came up with on my own and needs improvement. Maybe
the example given in
https://github.com/astral-sh/ruff/issues/2954#issuecomment-1441162976
could be used, but maybe they are too complex, I'm not sure.

## Open Questions

- [ ] Documentation. (See above.)

- [x] Can I access the parent in a visitor?

The [original
implementation](d1aec4cbef/bugbear.py (L1100))
references the `yield` statement's parent to check if it is an
expression statement. I didn't find a way to do this in `ruff` and used
the `is_expresssion_statement` field on the visitor instead. What are
your thoughts on this? Is it possible and / or desired to access the
parent node here?

- [x] Is `Option::is_some(...)` -> `...unwrap()` the right thing to do?

Referring to [this piece of
code](9d5a280f71/crates/ruff_linter/src/rules/flake8_bugbear/rules/return_x_in_generator.rs?plain=1#L91-L96).
From my understanding, the `.unwrap()` is safe, because it is checked
that `return_` is not `None`. However, I feel like I missed a more
elegant solution that does both in one.

## Other

I don't know a lot about this rule, I just implemented it because I
found it in a
https://github.com/astral-sh/ruff/labels/good%20first%20issue.

I'm new to Rust, so any constructive critisism is appreciated.

---------

Co-authored-by: Charlie Marsh <charlie.r.marsh@gmail.com>
2024-05-31 21:48:36 +00:00
Charlie Marsh 91a5fdee7a
Use find in indent detection (#11650) 2024-05-31 20:35:19 +00:00
Charlie Marsh 1ad5f9c038
Bump version to v0.4.7 (#11646) 2024-05-31 16:30:36 -04:00
plredmond e914bc300b
F401 sort bindings before adding to __all__ (#11648)
Sort the binding IDs before passing them to the add-to-`__all__`
function to address #11619.
2024-05-31 20:29:08 +00:00
Carl Meyer 27f6f048f0
[red-knot] initial (very incomplete) flow graph (#11624)
<!--
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

Introduces the skeleton of the flow graph. So far it doesn't actually
handle any non-linear control flow :) But it does show how we can go
from an expression that references a symbol, backward through the flow
graph, to find reachable definitions of that symbol.

Adding non-linear control flow will mean adding flow nodes with multiple
predecessors, which will introduce more complexity into
`ReachableDefinitionsIterator.next()`. But one step at a time.

## Test Plan

Added a (very basic) test.
2024-05-31 14:27:17 -06:00
Alex Waygood d62a617938
red-knot: Don't refer to `Module` instances as IDs (#11649) 2024-05-31 20:04:47 +00:00
Carl Meyer 16a926d138
[red-knot] infer int literal types (#11623)
## Summary

Give red-knot the ability to infer int literal types. This is quick and
easy, mostly because these types are a convenient way to observe
control-flow handling with simple assignments.

## Test Plan

Added test.
2024-05-31 13:52:29 -06:00
JaRoSchm 7ce17b7736
Add Vim and Kate setup guide for `ruff server` (#11615)
## Summary

In the [roadmap for `ruff
server`](https://github.com/astral-sh/ruff/discussions/10581) support
for vim and kate is listed. Therefore I added setup guides for them
based on the neovim guide. As I don't use pyright I wasn't able to
translate the corresponding part from the neovim guide.

## Test Plan

Doesn't apply.
2024-05-31 19:06:55 +00:00
Charlie Marsh f9a64503c8
Use char index rather than position for indent slice (#11645)
## Summary

A beginner's mistake :)

Closes https://github.com/astral-sh/ruff/issues/11641.
2024-05-31 19:04:36 +00:00
Alex Waygood 8a25531a71
red-knot: improve internal documentation in `module.rs` (#11638) 2024-05-31 16:11:18 +00:00
Micha Reiser 9b6d2ce1f2
Fix incorect placement of trailing stub function comments (#11632) 2024-05-31 12:06:17 +00:00
T-256 5b500fc4dc
`ruff server`: Add support for documents not exist on disk (#11588)
Co-authored-by: T-256 <Tester@test.com>
Co-authored-by: Micha Reiser <micha@reiser.io>
2024-05-31 08:34:10 +02:00
Charlie Marsh 685d11a909
Mark `repeated-isinstance-calls` as unsafe on Python 3.10 and later (#11622)
## Summary

Closes https://github.com/astral-sh/ruff/issues/11616.
2024-05-30 18:05:24 +00:00
plredmond dcabd04caf
F401 use BTreeMap instead of FxHashMap (#11621)
* Potentially resolves #11619 (nondeterministic hashmap order across
different architectures) in F401 by replacing a hashmap with
nondeterministic traversal order with an ordered mapping.

I'm not sure how to test this with our CI/CD. I don't have an s390x
machine at home. Should I try it in Qemu?
2024-05-30 10:54:46 -07:00
Charlie Marsh 3aa7e35a4c
Avoid removing newlines between docstring headers and rST blocks (#11609)
Given:

```python
def func():
    """
    Example:

    .. code-block:: python

        import foo
    """
```

Removing the newline after the `Example:` header breaks Sphinx
rendering.

See: https://github.com/astral-sh/ruff/issues/11577
2024-05-30 13:29:20 -04:00
Charlie Marsh bd46cd1fcf
Infer indentation with imports when logical indent is absent (#11608)
## Summary

In an `__init__.py` file, it's not uncommon to lack a logical indent
(since it may just contain imports). In such cases, we were always
falling back to four-space indent. This PR adds detection for indents
within import groups.

Closes https://github.com/astral-sh/ruff/issues/11606.
2024-05-30 00:18:07 -04:00
Charlie Marsh a8d1328c1a
[`flake8-comprehension`] Strip parentheses around generators in C400 (#11607)
## Summary

Closes https://github.com/astral-sh/ruff/issues/11603.
2024-05-30 03:26:56 +00:00
Christoph Hasse e35deee583
fix(F822): add option to enable F822 in __init__.py files (#11370)
## Summary

This PR aims to close #10095 by adding an option
`init-allow-undef-export` to the `pyflakes` settings. This option is
currently set to `true` such that behavior is kept identical.
But setting this option to `false` will lead to `F822` warnings to be
shown in all files, **including** `__init__.py` files.

As I've mentioned on #10095, I think `init-allow-undef-export=false`
would be the more user-friendly default option, as it creates fewer
surprises. @charliermarsh what do you think about making that the
default?

With this option in place, it's a single line fix for people that rely
on the old behavior.

And thinking longer term, for future major releases, one could probably
consider deprecating the option and eventually having people just `noqa`
these warnings if they are not wanted.


## Test Plan

I've added a `test_init_f822_enabled` test which repeats the test that
is done in the `init` test but this time with
`init-allow-undef-export=false` and the snap file correctly shows that
ruff will then trigger the otherwise suppressed F822 warning.


closes #10095
2024-05-30 03:15:05 +00:00
Micha Reiser 921bc15542
use owned ast and tokens in bench (#11598) 2024-05-29 18:10:32 +02:00
Vitaliy e14096f0a8
docs: Minor formatting typo in F401 example. (#11601)
## Summary

Removed stray space in sample code snippet that is against ruff's own
default formatting rules.

This documentation appears on
https://docs.astral.sh/ruff/rules/unused-import/

## Test Plan

This is a trivially obvious change, verifiable with `ruff format
--check`
2024-05-29 11:14:53 -04:00
Tomas R 7659114eb3
[flake8-pyi] Implement PYI057 (#11486)
Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
2024-05-29 10:04:36 +00:00
Micha Reiser 163c374242
Reduce extensive use of `snapshot.query` (#11596) 2024-05-29 10:11:46 +02:00
Charlie Marsh 204c59e353
Respect file exclusions in `ruff server` (#11590)
## Summary

Closes https://github.com/astral-sh/ruff/issues/11587.

## Test Plan

- Added a lint error to `test_server.py` in `vscode-ruff`.
- Validated that, prior to this change, diagnostics appeared in the
file.
- Validated that, with this change, no diagnostics were shown.
- Validated that, with this change, no diagnostics were fixed on-save.
2024-05-29 02:58:36 +00:00
Tushar Sadhwani 531ae5227c
[`flake8-pyi`] Implement `PYI066` (#11541)
## Summary

- Implements `Y066` from `flake8-pyi` as `PYI066`
- Fixes `PYI006` not being raised for `elif` clauses. This would have
conflicted with PYI006's implementation, so decided to do it in the same
PR.

## Test Plan

`cargo test` / `cargo insta review`
2024-05-29 00:30:00 +00:00
Tushar Sadhwani e0169d8dea
[`flake8-pyi`] Implement `PYI064` (#11325)
## Summary

Implements `Y064` from `flake8-pyi` and its autofix.

## Test Plan

`cargo test` / `cargo insta review`
2024-05-28 23:57:13 +00:00
plredmond 9a3b9f9fb5
[redknot] add module type and attribute lookup for some types (#11416)
* Add a module type, `ModuleTypeId`
* Add an attribute lookup method `get_member` for `Type`
  * Only implemented for `ModuleTypeId` and `ClassTypeId`
  * [x] Should this be a trait?
    *Answer: no*
* [x] Uses `unwrap`, but we should remove that. Maybe add a new variant
to `QueryError`?
    *Answer: Return `Option<Type>` as is done elsewhere*
* Add `infer_definition_type` case for `Import`
* Add `infer_expr_type` case for `Attribute`
* Add a test to exercise these
* [x] remove all NOTE/FIXME/TODO after discussing with reviewers
2024-05-28 13:13:03 -07:00
Charlie Marsh 49a5a9ccc2
Bump version to v0.4.6 (#11585) 2024-05-28 15:10:53 -04:00
Charlie Marsh 69d9212817
Propagate reads on global variables (#11584)
## Summary

This PR ensures that if a variable is bound via `global`, and then the
`global` is read, the originating variable is also marked as read. It's
not perfect, in that it won't detect _rebindings_, like:

```python
from app import redis_connection

def func():
    global redis_connection

    redis_connection = 1
    redis_connection()
```

So, above, `redis_connection` is still marked as unused.

But it does avoid flagging `redis_connection` as unused in:

```python
from app import redis_connection

def func():
    global redis_connection

    redis_connection()
```

Closes https://github.com/astral-sh/ruff/issues/11518.
2024-05-28 14:47:05 -04:00
Akshet Pandey 4a305588e9
[`flake8-bandit`] `request-without-timeout` should warn for `requests.request` (#11548)
## Summary
Update
[S113](https://docs.astral.sh/ruff/rules/request-without-timeout/) to
also warns for missing timeout on when calling `requests.request`
2024-05-28 16:31:12 +00:00
Charlie Marsh 16acd4913f
Remove some unused `pub` functions (#11576)
## Summary

I left anything in `red-knot`, any `with_` methods, etc.
2024-05-28 09:56:51 -04:00
Micha Reiser 3989cb8b56
Make `ruff_notebook` a workspace dependency in `ruff_server` (#11572) 2024-05-28 09:26:39 +02:00
Charlie Marsh a38c05bf13
Avoid recommending context manager in `__enter__` implementations (#11575)
## Summary

Closes https://github.com/astral-sh/ruff/issues/11567.
2024-05-28 01:44:24 +00:00
Charlie Marsh ab107ef1f3
Avoid recomending operator.itemgetter with dependence on lambda arg (#11574)
## Summary

Closes https://github.com/astral-sh/ruff/issues/11573.
2024-05-28 01:29:29 +00:00
Ahmed Ilyas b36c713279
Consider irrefutable pattern similar to `if .. else` for `C901` (#11565)
## Summary

Follow up to https://github.com/astral-sh/ruff/pull/11521

Removes the extra added complexity for catch all match cases. This
matches the implementation of plain `else` statements.

## Test Plan
Added new test cases.

---------

Co-authored-by: Dhruv Manilawala <dhruvmanila@gmail.com>
2024-05-27 17:33:36 +00:00
Charlie Marsh 34a5063aa2
Respect excludes in `ruff server` configuration discovery (#11551)
## Summary

Right now, we're discovering configuration files even within (e.g.)
virtual environments, because we're recursing without respecting the
`exclude` field on parent configuration.

Closes https://github.com/astral-sh/ruff-vscode/issues/478.

## Test Plan

Installed Pandas; verified that I saw no warnings:

![Screenshot 2024-05-26 at 8 09
05 PM](https://github.com/astral-sh/ruff/assets/1309177/dcf4115c-d7b3-453b-b7c7-afdd4804d6f5)
2024-05-27 16:59:46 +00:00
Micha Reiser adc0a5d126
Rename document module to text_document (#11571) 2024-05-27 18:32:21 +02:00
Dhruv Manilawala e28e737296
Update `FStringElements` to deref to a slice (#11570)
Ref: https://github.com/astral-sh/ruff/pull/11400#discussion_r1615600354
2024-05-27 15:52:13 +00:00
Dhruv Manilawala 37ad994318
Use default settings if initialization options is empty or not provided (#11566)
## Summary

This PR fixes the bug to avoid flattening the global-only settings for
the new server.

This was added in https://github.com/astral-sh/ruff/pull/11497, possibly
to correctly de-serialize an empty value (`{}`). But, this lead to a bug
where the configuration under the `settings` key was not being read for
global-only variant.

By using #[serde(default)], we ensure that the settings field in the
`GlobalOnly` variant is optional and that an empty JSON object `{}` is
correctly deserialized into `GlobalOnly` with a default `ClientSettings`
instance.

fixes: #11507 

## Test Plan

Update the snapshot and existing test case. Also, verify the following
settings in Neovim:

1. Nothing

```lua
ruff = {
  cmd = {
    '/Users/dhruv/work/astral/ruff/target/debug/ruff',
    'server',
    '--preview',
  },
}
```

2. Empty dictionary

```lua
ruff = {
  cmd = {
    '/Users/dhruv/work/astral/ruff/target/debug/ruff',
    'server',
    '--preview',
  },
  init_options = vim.empty_dict(),
}
```

3. Empty `settings`

```lua
ruff = {
  cmd = {
    '/Users/dhruv/work/astral/ruff/target/debug/ruff',
    'server',
    '--preview',
  },
  init_options = {
    settings = vim.empty_dict(),
  },
}
```

4. With some configuration:

```lua
ruff = {
  cmd = {
    '/Users/dhruv/work/astral/ruff/target/debug/ruff',
    'server',
    '--preview',
  },
  init_options = {
    settings = {
      configuration = '/tmp/ruff-repro/pyproject.toml',
    },
  },
}
```
2024-05-27 21:06:34 +05:30
Alex Waygood 246a3388ee
Implement a common trait for the string flags (#11564) 2024-05-27 16:02:01 +01:00
Dhruv Manilawala 9200dfc79f
Remove empty strings when converting to f-string (`UP032`) (#11524)
## Summary

This PR brings back the functionality to remove empty strings when
converting to an f-string in `UP032`.

For context, https://github.com/astral-sh/ruff/pull/8712 added this
functionality to remove _trailing_ empty strings but it got removed in
https://github.com/astral-sh/ruff/pull/8697 possibly unexpectedly so.

There's one difference which is that this PR will remove _any_ empty
strings and not just trailing ones. For example,

```diff
--- /Users/dhruv/playground/ruff/src/UP032.py
+++ /Users/dhruv/playground/ruff/src/UP032.py
@@ -1,7 +1,5 @@
 (
-    "{a}"
-    ""
-    "{b}"
-    ""
-).format(a=1, b=1)
+    f"{1}"
+    f"{1}"
+)
```

## Test Plan

Run `cargo insta test` and update the snapshots.
2024-05-27 05:05:22 +00:00
Dhruv Manilawala 99c400000a
Avoid owned token data in sequence sorting (#11533)
## Summary

This PR updates the sequence sorting (`RUF022` and `RUF023`) to avoid
using the owned data from the string token. Instead, we will directly
use the reference to the data on the AST. This does introduce a lot of
lifetimes but that's required.

The main motivation for this is to allow removing the `lex_starts_at`
usage easily.

### Alternatives

1. Extract the raw string content (stripping the prefix and quotes)
using the `Locator` and use that for comparison
2. Build up an
[`IndexVec`](3e30962077/crates/ruff_index/src/vec.rs)
and use the newtype index in place of the string value itself. This also
does require lifetimes so we might as well just use the method in this
PR.

## Test Plan

`cargo insta test` and no ecosystem changes
2024-05-26 20:20:20 -04:00
Charlie Marsh b5d147d219
Create intermediary directories for `--output-file` (#11550)
Closes https://github.com/astral-sh/ruff/issues/11549.
2024-05-26 23:23:11 +00:00
Aleksei Latyshev 77da4615c1
[`pyupgrade`] Support `TypeAliasType` in `UP040` (#11530)
## Summary
Lint `TypeAliasType` in UP040.

Fixes #11422 

## Test Plan

cargo test
2024-05-26 19:05:35 +00:00
Jane Lewis 627d230688
`ruff server` searches for configuration in parent directories (#11537)
## Summary

Fixes #11506.

`RuffSettingsIndex::new` now searches for configuration files in parent
directories.

## Test Plan

I confirmed that the original test case described in the issue worked as
expected.
2024-05-26 18:11:08 +00:00
Fergus Longley 0eef834e89
Use project-relative path when calculating gitlab message fingerprint (#11532)
## Summary

Concurrent GitLab runners clone projects into separate directories, e.g.
`{builds_dir}/$RUNNER_TOKEN_KEY/$CONCURRENT_ID/$NAMESPACE/$PROJECT_NAME`.
Since the fingerprint uses the full path to the file, the fingerprints
calculated by Ruff are different depending on which concurrent runner it
executes on, so often an MR will appear to remove all existing issues
and add them with new fingerprints.

I've adjusted the fingerprint function to use the project relative path,
which fixes this. Unfortunately this will have a breaking change for any
current users of this output - the fingerprints will change and appear
in GitLab as all linting messages having been fixed and then created.

## Test Plan

`cargo nextest run`

Running `ruff check --output-format gitlab` in a git repo, moving the
repo and running again, verifying no diffs between the outputs
2024-05-26 14:10:04 -04:00
Charlie Marsh 650c578e07
[`flake8-self`] Ignore sunder accesses in `flake8-self` rule (#11546)
## Summary

We already ignore dunders, so ignoring sunders (as in
https://docs.python.org/3/library/enum.html#supported-sunder-names)
makes sense to me.
2024-05-26 13:57:24 -04:00
Jane Lewis 9567fddf69
`ruff server` correctly treats `.pyi` files as stub files (#11535)
## Summary

Fixes #11534.

`DocumentQuery::source_type` now returns `PySourceType::Stub` when the
document is a `.pyi` file.

## Test Plan

I confirmed that stub-specific rule violations appeared with a build
from this PR (they were not visible from a `main` build).

<img width="1066" alt="Screenshot 2024-05-24 at 2 15 38 PM"
src="https://github.com/astral-sh/ruff/assets/19577865/cd519b7e-21e4-41c8-bc30-43eb6d4d438e">
2024-05-26 13:42:48 -04:00
Mateusz Sokół ab6d9d4658
Add missing functions to NumPy 2.0 migration rule (#11528)
Hi! 

I left out some of the functions in the migration rule which became
removed in NumPy 2.0:
- `np.alltrue`
- `np.anytrue`
- `np.cumproduct`
- `np.product`

Addressing: https://github.com/numpy/numpy/issues/26493
2024-05-26 13:24:20 -04:00
Amar Paul 677893226a
[`flake8-2020`] fix minor typo in `YTT301` documentation (#11543)
## Summary

<!-- What's the purpose of the change? What does it do, and why? -->
Current doc says `sys.version[0]` will select the first digit of a major
version number (correct) then as an example says

> e.g., `"3.10"` would evaluate to `"1"`

(would actually evaluate to `"3"`). Changed the example version to a
two-digit number to make the problem more clear.

## Test Plan

<!-- How was it tested? -->
ran the following:
- `cargo run -p ruff -- check
crates/ruff_linter/resources/test/fixtures/flake8_2020/YTT301.py
--no-cache`
- `cargo insta review`
- `cargo test`
which all passed.
2024-05-26 13:23:41 -04:00
Ahmed Ilyas 33fd50027c
Consider match-case stmts for `C901`, `PLR0912`, and `PLR0915` (#11521)
Resolves #11421

## Summary

Instead of counting match/case as one statement, consider each `case` as
a conditional.

## Test Plan

`cargo test`
2024-05-24 14:44:46 +05:30
Dmitry Bogorad 3e30962077
[`flake8-logging-format`] Fix the autofix title in `logging-warn` (`G010`) (#11514)
## Summary

Rule `logging-warn` (`G010`) prescribes a change from `warn` to
`warning` and has a corresponding autofix, but the autofix is mistakenly
titled ```"Convert to `warn`"``` instead of ```"Convert to `warning`"```
(the latter is what the autofix actually does). Seems to be a plain
typo.
2024-05-24 13:13:42 +05:30
Jane Lewis 81275a6c3d
`ruff server`: An empty code action filter no longer returns notebook source actions (#11526)
## Summary

Fixes #11516

`ruff server` was sending both regular source actions and notebook
source actions back when passed an empty action filter. This PR makes a
few small changes so that notebook source actions are not sent when
regular source actions are sent, which means that an empty filter will
only return regular source actions.

## Test Plan

I confirmed that duplicate code actions no longer appeared in Neovim,
using a configuration similar to the one from the original issue.

<img width="509" alt="Screenshot 2024-05-23 at 11 48 48 PM"
src="https://github.com/astral-sh/ruff/assets/19577865/9a5d6907-dd41-48bd-b015-8a344c5e0b3f">
2024-05-24 07:20:39 +00:00
Charlie Marsh 52c946a4c5
Treat all `singledispatch` arguments as runtime-required (#11523)
## Summary

It turns out that `singledispatch` does end up evaluating all arguments,
even though only the first is used to dispatch.

Closes https://github.com/astral-sh/ruff/issues/11520.
2024-05-23 20:36:24 -04:00
Evan Kohilas ebdaf5765a
[flake8-async] Sleep with >24 hour interval should usually sleep forever (ASYNC116) (#11498)
## Summary

Addresses #8451 by implementing rule 116 to add an unsafe fix when sleep
is used with a >24 hour interval to instead consider sleeping forever.

This rule is added as async instead as I my understanding was that these
trio rules would be moved to async anyway.

There are a couple of TODOs, which address further extending the rule by
adding support for lookups and evaluations, and also supporting `anyio`.
2024-05-23 16:25:50 -04:00
Dhruv Manilawala 102b9d930f
Use `Importer` available on `Checker` (#11513)
## Summary

This PR updates the `FA102` rule logic to use the `Importer` which is
available on the `Checker`.

The main motivation is that this would make updating the `Importer` to
use the `Tokens` struct which will be required to remove the
`lex_starts_at` usage in `Insertion::start_of_block` method.

## Test Plan

`cargo insta test`
2024-05-23 11:19:08 +00:00
Jane Lewis 550aa871d3
Bump version to `v0.4.5` (#11502) 2024-05-23 01:09:01 +00:00
Charlie Marsh 3c22a3bdcc
Minor edits to `ruff server` docs (#11500)
## Summary

Minor copy edits based on my read-through. Feel free to disagree
anywhere.
2024-05-22 23:53:53 +00:00
Jane Lewis 6263923915
Update documentation for `ruff server` with new migration guide (#11499)
## Summary

Introduces a migration guide from `ruff-lsp` to `ruff server` and makes
small updates to the `README.md`.
2024-05-22 14:36:33 -07:00
Jane Lewis 94abea4b08
`ruff server`: Fix multiple issues with Neovim and Helix (#11497)
## Summary

Fixes https://github.com/astral-sh/ruff/issues/11236.

This PR fixes several issues, most of which relate to non-VS Code
editors (Helix and Neovim).

1. Global-only initialization options are now correctly deserialized
from Neovim and Helix
2. Empty diagnostics are now published correctly for Neovim and Helix.
3. A workspace folder is created at the current working directory if the
initialization parameters send an empty list of workspace folders.
4. The server now gracefully handles opening files outside of any known
workspace, and will use global fallback settings taken from client
editor settings and a user settings TOML, if it exists.

## Test Plan

I've tested to confirm that each issue has been fixed.

* Global-only initialization options are now correctly deserialized from
Neovim and Helix + the server gracefully handles opening files outside
of any known workspace


https://github.com/astral-sh/ruff/assets/19577865/4f33477f-20c8-4e50-8214-6608b1a1ea6b

* Empty diagnostics are now published correctly for Neovim and Helix


https://github.com/astral-sh/ruff/assets/19577865/c93f56a0-f75d-466f-9f40-d77f99cf0637

* A workspace folder is created at the current working directory if the
initialization parameters send an empty list of workspace folders.



https://github.com/astral-sh/ruff/assets/19577865/b4b2e818-4b0d-40ce-961d-5831478cc726
2024-05-22 20:50:58 +00:00
Charlie Marsh 519a65007f
Mark quotes as unnecessary for non-evaluated annotations (#11485)
## Summary

Similar to #11414, this PR extends `UP037` to flag quoted annotations
that are located in positions that won't be evaluated at runtime.

For example, the quotes on `Tuple` are unnecessary in:

```python
from typing import TYPE_CHECKING

if TYPE_CHECKING:
    from typing import Tuple


def foo():
    x: "Tuple[int, int]" = (0, 0)

foo()
```
2024-05-22 15:44:31 -04:00
Jane Lewis 573facd2ba
Fix automatic configuration reloading for text and notebook documents (#11492)
## Summary

Recent changes made in the [Jupyter Notebook feature
PR](https://github.com/astral-sh/ruff/pull/11206) caused automatic
configuration reloading to stop working. This was because we would check
for paths to reload using the changed path, when we should have been
using the parent path of the changed path (to get the directory it was
changed in).

Additionally, this PR fixes an issue where `ruff.toml` and `.ruff.toml`
files were not being automatically reloaded.

Finally, this PR improves configuration reloading by actively publishing
diagnostics for notebook documents (which won't be affected by the
workspace refresh since they don't use pull diagnostics). It will also
publish diagnostics for text documents if pull diagnostics aren't
supported.

## Test Plan
To test this, open an existing configuration file in a codebase, and
make modifications that will affect one or more open Python / Jupyter
Notebook files. You should observe that the diagnostics for both kinds
of files update automatically when the file changes are saved.

Here's a test video showing what a successful test should look like:



https://github.com/astral-sh/ruff/assets/19577865/7172b598-d6de-4965-b33c-6cb8b911ef6c
2024-05-22 11:20:45 -07:00
Jane Lewis 3cb2e677aa
`ruff.applyFormat` now formats an entire notebook document (#11493)
## Summary

Previously, `ruff.applyFormat`, seen in VS Code as the command `Ruff:
Format Document`, would only format the currently active notebook cell
inside a notebook document. This PR makes `ruff.applyFormat` format the
entire notebook document at once, operating on each code cell in order.

## Test Plan

1. Open a notebook document that has multiple unformatted code cells.
2. Run `Ruff: Format Document` through the Command Palette
(`Ctrl/Cmd+Shift+P` by default)
3. Observe that all code cells in the notebook have been formatted.
2024-05-22 09:02:46 -07:00
Dhruv Manilawala f0046ab28e
Move `has_comments` to `CommentRanges` (#11495)
## Summary

This PR moves the `has_comments` function from `Indexer` to
`CommentRanges`. The main motivation is that the `CommentRanges` will
now be built by the parser which is shared between the linter and the
formatter. Thus, the `CommentRanges` will be removed from the `Indexer`.

## Test Plan

`cargo test`
2024-05-22 13:35:16 +00:00
Charlie Marsh 5bb9720a10
Avoid multiline quotes warning with `quote-style = preserve` (#11490)
## Summary

Closes https://github.com/astral-sh/ruff/issues/11063.
2024-05-22 04:31:03 +00:00
Charlie Marsh aa906b9c75
[`pylint`] Ignore `__slots__` with dynamic values (#11488)
## Summary

Closes https://github.com/astral-sh/ruff/issues/11333.
2024-05-22 04:18:01 +00:00
Charlie Marsh 8848eca3c6
[`pylint`] Remove `try` body from branch counting (#11487)
## Summary

Matching Pylint, we now omit the `try` body itself from branch counting.
Each `except` counts as a branch, as does the `else` and the `finally`.

Closes https://github.com/astral-sh/ruff/issues/11205.
2024-05-21 23:38:51 -04:00
Jane Lewis b0731ef9cb
`ruff server`: Support Jupyter Notebook (`*.ipynb`) files (#11206)
## Summary

Closes https://github.com/astral-sh/ruff/issues/10858.

`ruff server` now supports `*.ipynb` (aka Jupyter Notebook) files.
Extensive internal changes have been made to facilitate this, which I've
done some work to contextualize with documentation and an pre-review
that highlights notable sections of the code.

`*.ipynb` cells should behave similarly to `*.py` documents, with one
major exception. The format command `ruff.applyFormat` will only apply
to the currently selected notebook cell - if you want to format an
entire notebook document, use `Format Notebook` from the VS Code context
menu.

## Test Plan

The VS Code extension does not yet have Jupyter Notebook support
enabled, so you'll first need to enable it manually. To do this,
checkout the `pre-release` branch and modify `src/common/server.ts` as
follows:

Before:
![Screenshot 2024-05-13 at 10 59
06 PM](https://github.com/astral-sh/ruff/assets/19577865/c6a3c604-c405-4968-b8a2-5d670de89172)

After:
![Screenshot 2024-05-13 at 10 58
24 PM](https://github.com/astral-sh/ruff/assets/19577865/94ab2e3d-0609-448d-9c8c-cd07c69a513b)

I recommend testing this PR with large, complicated notebook files. I
used notebook files from [this popular
repository](https://github.com/jakevdp/PythonDataScienceHandbook/tree/master/notebooks)
in my preliminary testing.

The main thing to test is ensuring that notebook cells behave the same
as Python documents, besides the aforementioned issue with
`ruff.applyFormat`. You should also test adding and deleting cells (in
particular, deleting all the code cells and ensure that doesn't break
anything), changing the kind of a cell (i.e. from markup -> code or vice
versa), and creating a new notebook file from scratch. Finally, you
should also test that source actions work as expected (and across the
entire notebook).

Note: `ruff.applyAutofix` and `ruff.applyOrganizeImports` are currently
broken for notebook files, and I suspect it has something to do with
https://github.com/astral-sh/ruff/issues/11248. Once this is fixed, I
will update the test plan accordingly.

---------

Co-authored-by: nolan <nolan.king90@gmail.com>
2024-05-21 22:29:30 +00:00
Nicolas Jeker 84531d1644
Clarify motivation for E713 and E714 (#11483)
The wording 'negative comparison' is a rather vague description of the
'is not' operation and does not describe what the 'not in' operation
does (potentially copied from 'is not'). This was replaced with more
precise language to describe the operators taken from the official
python docs[1].

Both rules didn't have a strong reasoning besides 'it's bad, use the
other'. The origin of these rules seems to be PEP8[2] which prefers 'is
not' over 'not ... is' for readability. This is now reflected in the
description.

[1]:
https://docs.python.org/3/reference/expressions.html#membership-test-operations
[2]: https://peps.python.org/pep-0008/#programming-recommendations
2024-05-21 14:12:18 -05:00
Charlie Marsh 83b8b62e3e
Avoid flagging `__future__` annotations as required for non-evaluated type annotations (#11414)
## Summary

If an annotation won't be evaluated at runtime, we don't need to flag
`from __future__ import annotations` as required. This applies both to
quoted annotations and annotations outside of runtime-evaluated
positions, like:

```python
def main() -> None:
    a_list: list[str] | None = []
    a_list.append("hello")
```

Closes https://github.com/astral-sh/ruff/issues/11397.
2024-05-21 18:57:13 +00:00
plredmond 7225732859
F401 - update documentation and deprecate `ignore_init_module_imports` (#11436)
## Summary

* Update documentation for F401 following recent PRs
  * #11168
  * #11314
* Deprecate `ignore_init_module_imports`
* Add a deprecation pragma to the option and a "warn user once" message
when the option is used.
* Restore the old behavior for stable (non-preview) mode:
* When `ignore_init_module_imports` is set to `true` (default) there are
no `__init_.py` fixes (but we get nice fix titles!).
* When `ignore_init_module_imports` is set to `false` there are unsafe
`__init__.py` fixes to remove unused imports.
* When preview mode is enabled, it overrides
`ignore_init_module_imports`.
* Fixed a bug in fix titles where `import foo as bar` would recommend
reexporting `bar as bar`. It now says to reexport `foo as foo`. (In this
case we don't issue a fix, fwiw; it was just a fix title bug.)

## Test plan

Added new fixture tests that reuse the existing fixtures for
`__init__.py` files. Each of the three situations listed above has
fixture tests. The F401 "stable" tests cover:

> * When `ignore_init_module_imports` is set to `true` (default) there
are no `__init_.py` fixes (but we get nice fix titles!).

The F401 "deprecated option" tests cover:

> * When `ignore_init_module_imports` is set to `false` there are unsafe
`__init__.py` fixes to remove unused imports.

These complement existing "preview" tests that show the new behavior
which recommends fixes in `__init__.py` according to whether the import
is 1st party and other circumstances (for more on that behavior see:
#11314).
2024-05-21 09:23:45 -07:00
Dhruv Manilawala 403f0dccd8
Consider soft keywords for `E27` rules (#11446)
## Summary

This is a follow-up PR to #11445 update the `E27` rules to consider soft
keywords as well.

## Test Plan

Add test cases consisting of soft keywords and update the snapshot.
2024-05-20 05:38:06 +00:00
Charlie Marsh cfceb437a8
Treat escaped newline as valid sequence (#11465)
## Summary

We weren't treating the escaped newline as a valid condition to trigger
the safer fix (add an extra backslash before each invalid escape
sequence).

Closes https://github.com/astral-sh/ruff/issues/11461.
2024-05-19 03:32:32 +00:00
Charlie Marsh 48b0660228
Respect operator precedence in `FURB110` (#11464)
## Summary

Ensures that we parenthesize expressions (if necessary) to preserve
operator precedence in `FURB110`.

Closes https://github.com/astral-sh/ruff/issues/11398.
2024-05-19 03:17:11 +00:00
Charlie Marsh 24899efe50
Remove example from `tab-indentation` (#11462)
## Summary

I think the example is more confusing than helpful, since there's no
visual difference between the tab and space here (even if it rendered
properly).

Closes
https://github.com/astral-sh/ruff/issues/11460#issuecomment-2118397278.
2024-05-17 17:49:16 -04:00
Dhruv Manilawala 83152fff92
Include soft keywords for `is_keyword` check (#11445)
## Summary

This PR updates the `TokenKind::is_keyword` check to include soft
keywords. To account for this change, it adds a new
`is_non_soft_keyword` method.

The usage in logical line rules were updated to use the
`is_non_soft_keyword` method but it'll be updated to use `is_keyword` in
a follow-up PR (#11446).

While, the parser usages were kept as is. And because of that, the
snapshots for two test cases were updated in a better direction.

## Test Plan

`cargo insta test`
2024-05-17 10:26:48 +05:30
Charlie Marsh 43e8147eaf
Sort edits prior to deduplicating in quotation fix (#11452)
## Summary

We already have handling for "references that get quoted within our
quoted references", but we were assuming a specific ordering in the way
edits were generated.

Closes https://github.com/astral-sh/ruff/issues/11449.
2024-05-16 12:13:09 -04:00
Dhruv Manilawala f67c02c837
Remove leftover marker tokens (#11444)
## Summary

This PR removes the leftover marker tokens from the LALRPOP to
hand-written parser migration.
2024-05-16 11:39:05 +00:00
Charlie Marsh 4436dec1d9
Fix broken comment in `too-many-branches` (#11440) 2024-05-16 02:25:20 +00:00
Tim Hatch 27da223e9f
Add `--output-format` to `ruff config` CLI (#11438)
This is useful for extracting the defaults in order to construct
equivalent configs by external scripts. This is my first non-hello-world
rust code, comments and suggested tests appreciated.

## Summary

We already have `ruff linter --output-format json`, this provides `ruff
config x --output-format json` as well. I plan to use this to construct
an equivalent config snippet to include in some managed repos, so when
we update their version of ruff and it adds new lints, they get a PR
that includes the commented-out new lints.

Note that the no-args form of `ruff config` ignores output-format
currently, but probably should obey it (although array-of-strings
doesn't seem that useful, looking for input on format).

## Test Plan

I could use a hand coming up with a typical way to write automated tests
for this.

```sh-session
(.venv) [timhatch:ruff ]$ ./target/debug/ruff config lint.select
A list of rule codes or prefixes to enable. Prefixes can specify exact
rules (like `F841`), entire categories (like `F`), or anything in
between.

When breaking ties between enabled and disabled rules (via `select` and
`ignore`, respectively), more specific prefixes override less
specific prefixes.

Default value: ["E4", "E7", "E9", "F"]
Type: list[RuleSelector]
Example usage:
``toml
# On top of the defaults (`E4`, E7`, `E9`, and `F`), enable flake8-bugbear (`B`) and flake8-quotes (`Q`).
select = ["E4", "E7", "E9", "F", "B", "Q"]
``
(.venv) [timhatch:ruff ]$ ./target/debug/ruff config lint.select --output-format json
{
  "Field": {
    "doc": "A list of rule codes or prefixes to enable. Prefixes can specify exact\nrules (like `F841`), entire categories (like `F`), or anything in\nbetween.\n\nWhen breaking ties between enabled and disabled rules (via `select` and\n`ignore`, respectively), more specific prefixes override less\nspecific prefixes.",
    "default": "[\"E4\", \"E7\", \"E9\", \"F\"]",
    "value_type": "list[RuleSelector]",
    "scope": null,
    "example": "# On top of the defaults (`E4`, E7`, `E9`, and `F`), enable flake8-bugbear (`B`) and flake8-quotes (`Q`).\nselect = [\"E4\", \"E7\", \"E9\", \"F\", \"B\", \"Q\"]",
    "deprecated": null
  }
}
```
2024-05-15 22:17:33 -04:00
Jaap Roes b3e4d39f64
Clearly indicate what is counted as a branch (#11423)
## Summary

As discussed in issue #11408, PLR0912 has a broader definition of
"branches" than I expected. This updates the documentation to include
this definition.

I also updated the example to include several different types of
branches, while still maintaining dictionary lookup as an alternative
solution. (Crafting a realistic example was quite a challenge 😅).

Closes https://github.com/astral-sh/ruff/issues/11408.
2024-05-15 22:17:05 -04:00
Tim Hatch d05347cfcb
Regenerate sys.rs with stdlibs==2024.5.15 (#11437)
## Summary

Now that 3.13.0 b1 is out some of the stdlib modules have changed names.

## Test Plan

Wait for CI to run, expected to be pretty safe.
2024-05-15 22:17:32 +00:00
Alex Waygood 6963f75a14
Move string-prefix enumerations to a separate submodule (#11425)
## Summary

This moves the string-prefix enumerations in `ruff_python_ast` to a
separate submodule. I think this helps clarify that these prefixes are
purely abstract: they only depend on each other, and do not depend on
any of the other code in `nodes.rs` in any way. Moreover, while various
AST nodes _use_ them, they're not really nodes themselves, so they feel
slightly out of place in `nodes.rs`.

I considered moving all of them to `str.rs`, but it felt like enough
code that it could be a separate submodule.

## Test Plan

`cargo test`
2024-05-15 07:40:27 -04:00
github-actions[bot] effe3ad4ef
Sync vendored typeshed stubs (#11428)
Co-authored-by: typeshedbot <>
2024-05-15 00:46:41 +00:00
Alex Waygood bdc15a7cb9
Add automation for updating our vendored typeshed stubs (#11427) 2024-05-14 20:39:30 -04:00
plredmond da882b6657
F401 - Recommend adding unused import bindings to `__all__` (#11314)
Followup on #11168 and resolve #10391

# User facing changes

* F401 now recommends a fix to add unused import bindings to to
`__all__` if a single `__all__` list or tuple is found in `__init__.py`.
* If there are no `__all__` found in the file, fall back to recommending
redundant-aliases.
* If there are multiple `__all__` or only one but of the wrong type (non
list or tuple) then diagnostics are generated without fixes.
* `fix_title` is updated to reflect what the fix/recommendation is.

Subtlety: For a renamed import such as `import foo as bees`, we can
generate a fix to add `bees` to `__all__` but cannot generate a fix to
produce a redundant import (because that would break uses of the binding
`bees`).

# Implementation changes

* Add `name` field to `ImportBinding` to contain the name of the
_binding_ we want to add to `__all__` (important for the `import foo as
bees` case). It previously only contained the `AnyImport` which can give
us information about the import but not the binding.
* Add `binding` field to `UnusedImport` to contain the same. (Naming
note: the field `name` field already existed on `UnusedImport` and
contains the qualified name of the imported symbol/module)
* Change `fix_by_reexporting` to branch on the size of `dunder_all:
Vec<&Expr>`
* For length 0 call the edit-producing function `make_redundant_alias`.
  * For length 1 call edit-producing function `add_to_dunder_all`.
  * Otherwise, produce no fix.
* Implement the edit-producing function `add_to_dunder_all` and add unit
tests.
* Implement several fixture tests: empty `__all__ = []`, nonempty
`__all__ = ["foo"]`, mis-typed `__all__ = None`, plus-eq `__all__ +=
["foo"]`
* `UnusedImportContext::Init` variant now has two fields: whether the
fix is in `__init__.py` and how many `__all__` were found.

# Other changes

* Remove a spurious pattern match and instead use field lookups b/c the
addition of a field would have required changing the unrelated pattern.
* Tweak input type of `make_redundant_alias`

---------

Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
2024-05-14 17:02:33 -07:00
Dhruv Manilawala 96f6288622
Move `UP034` to use `TokenKind` instead of `Tok` (#11424)
## Summary

This PR follows up from #11420 to move `UP034` to use `TokenKind`
instead of `Tok`.

The main reason to have a separate PR is so that the reviewing is easy.
This required a lot more updates because the rule used an index (`i`) to
keep track of the current position in the token vector. Now, as it's
just an iterator, we just use `next` to move the iterator forward and
extract the relevant information.

This is part of https://github.com/astral-sh/ruff/issues/11401

## Test Plan

`cargo test`
2024-05-14 17:28:04 +00:00
Dhruv Manilawala bb1c107afd
Move most of token-based rules to use `TokenKind` (#11420)
## Summary

This PR moves the following rules to use `TokenKind` instead of `Tok`:
* `PLE2510`, `PLE2512`, `PLE2513`, `PLE2514`, `PLE2515`
* `E701`, `E702`, `E703`
* `ISC001`, `ISC002`
* `COM812`, `COM818`, `COM819`
* `W391`

I've paused here because the next set of rules
(`pyupgrade::rules::extraneous_parentheses`) indexes into the token
slice but we only have an iterator implementation. So, I want to isolate
that change to make sure the logic is still the same when I move to
using the iterator approach.

This is part of #11401 

## Test Plan

`cargo test`
2024-05-14 17:16:42 +00:00
Dhruv Manilawala c17193b5f8
Use `TokenKind` in blank lines checker (#11419)
## Summary

This PR updates the blank line rules checker to use `TokenKind` instead
of `Tok`.

This is part of #11401 

## Test Plan

`cargo test`
2024-05-14 17:07:35 +00:00
Dhruv Manilawala a33763170e
Use `TokenKind` in `doc_lines_from_tokens` (#11418)
## Summary

This PR updates the `doc_lines_from_tokens` function to use `TokenKind`
instead of `Tok`.

This is part of #11401 

## Test Plan

`cargo test`
2024-05-14 16:56:14 +00:00
Dhruv Manilawala 025768d303
Add `Tokens` newtype wrapper, `TokenKind` iterator (#11361)
## Summary

Alternative to #11237 

This PR adds a new `Tokens` struct which is a newtype wrapper around a
vector of lexer output. This allows us to add a `kinds` method which
returns an iterator over the corresponding `TokenKind`. This iterator is
implemented as a separate `TokenKindIter` struct to allow using the type
and provide additional methods like `peek` directly on the iterator.

This exposes the linter to access the stream of `TokenKind` instead of
`Tok`.

Edit: I've made the necessary downstream changes and plan to merge the
entire stack at once.
2024-05-14 16:45:04 +00:00
Dhruv Manilawala 50f14d017e
Use `tokenize` for linter benchmark (#11417)
## Summary

This PR updates the linter benchmark to use the `tokenize` function
instead of the lexer.

The linter expects the token list to be up to and including the first
error which is what the `ruff_python_parser::tokenize` function returns.

This was not a problem before because the benchmarks only uses valid
Python code.
2024-05-14 10:28:40 -04:00
Charlie Marsh 6ed2482e27
Add Python 3.13 to list of allowed Python versions (#11411)
## Summary

I believe we're already "Python 3.13-ready"? The main Ruff-impacting
change I see in https://docs.python.org/3.13/whatsnew/3.13.html is [PEP
696](https://peps.python.org/pep-0696/) which Jelle added in
https://github.com/astral-sh/ruff/pull/11120.
2024-05-13 16:35:41 +00:00
Charlie Marsh dc5c44ccc4
Remove some hardcoded modules from `generate_known_standard_library.py` (#11409)
See feedback in: https://github.com/astral-sh/ruff/pull/11374
2024-05-13 12:27:34 -04:00
Dhruv Manilawala c3c87e86ef
Implement `IntoIterator` for `FStringElements` (#11410)
A change which I lost somewhere when I force pushed in
https://github.com/astral-sh/ruff/pull/11400
2024-05-13 16:24:49 +00:00
Dhruv Manilawala ca99e9e2f0
Move `W605` to the AST checker (#11402)
## Summary

This PR moves the `W605` rule to the AST checker.

This is part of #11401

## Test Plan

`cargo test`
2024-05-13 16:13:06 +00:00
Dhruv Manilawala 4b41e4de7f
Create a newtype wrapper around `Vec<FStringElement>` (#11400)
## Summary

This PR adds a newtype wrapper around `Vec<FStringElement>` that derefs
to a `&Vec<FStringElement>`.

Both f-string and format specifier are made up of `Vec<FStringElement>`.
By creating a newtype wrapper around it, we can share the methods for
both parent types.
2024-05-13 16:04:04 +00:00
Dhruv Manilawala 0dc130e841
Add `Iterator` impl for `StringLike` parts (#11399)
## Summary

This PR adds support to iterate over each part of a string-like
expression.

This similar to the one in the formatter:


128414cd95/crates/ruff_python_formatter/src/string/any.rs (L121-L125)

Although I don't think it's a 1-1 replacement in the formatter because
the one implemented in the formatter has another information for certain
variants (as can be seen for `FString`).

The main motivation for this is to avoid duplication for rules which
work only on the parts of the string and doesn't require any information
from the parent node. Here, the parent node being the expression node
which could be an implicitly concatenated string.

This PR also updates certain rule implementation to make use of this and
avoids logic duplication.
2024-05-13 15:52:03 +00:00
Dhruv Manilawala 10b85a0f07
Avoid lexer usage in `PLE1300` and `PLE1307` (#11406)
## Summary

This PR updates `PLE1300` and `PLE1307` to avoid using the lexer.

This is part of #11401 

## Test Plan

`cargo test`
2024-05-13 10:48:44 -04:00
Charlie Marsh af60d539ab
Move sub-crates to workspace dependencies (#11407)
## Summary

This matches the setup we use in `uv` and allows for consistency in the
`Cargo.toml` files.
2024-05-13 14:37:50 +00:00
Dimitri Papadopoulos Orfanos 3b0584449d
Fix a few typos found by codespell (#11404)
## Summary

Just fix typos.

## Test Plan

CI jobs.

---------

Co-authored-by: Dhruv Manilawala <dhruvmanila@gmail.com>
2024-05-13 13:22:35 +00:00
Dhruv Manilawala 6ecb4776de
Rename `AnyStringKind` -> `AnyStringFlags` (#11405)
## Summary

This PR renames `AnyStringKind` to `AnyStringFlags` and `AnyStringFlags`
to `AnyStringFlagsInner`.

The main motivation is to have consistent usage of "kind" and "flags".
For each string kind, it's "flags" like `StringLiteralFlags`,
`BytesLiteralFlags`, and `FStringFlags` but it was `AnyStringKind` for
the "any" variant.
2024-05-13 13:18:07 +00:00
Charlie Marsh 6cec82fff8
Get `cargo shear` passing (#11392)
## Summary

Remove some unused dependencies, add a few ignores.
2024-05-13 01:56:24 +00:00
Tom Kuson 5ab4cc86c2
Reword `future-rewritable-type-annotation` (`FA100`) message (#11381)
## Summary

Changes `future-rewritable-type-annotation` (`FA100`) message to be less
confusing. Uses phrasing from the rule documentation to be consistent.
For example,

```
from_typing_import.py:5:13: FA100 Add `from __future__ import annotations` to rewrite `typing.List` more succinctly
```

Closes #10573.

## Test Plan

`cargo nextest run`
2024-05-13 01:38:49 +00:00
Rahul Modpur 6a28f3448e
Migrate sys.rs generation to stdlibs (#11374)
## Summary

Closes #11347
2024-05-12 21:21:51 -04:00
Dhruv Manilawala 0fc6cf9bee
Avoid `PLE0237` for property with setter (#11377)
## Summary

Should this consider the decorator only if the name is actually a
property or is the logic in this PR correct?

fixes: #11358

## Test Plan

Add test case.
2024-05-12 20:23:00 -04:00
Dhruv Manilawala d835b3e218
Avoid `TCH005` for `if` stmt with `elif`/`else` block (#11376)
## Summary

This PR fixes a bug where the auto-fix for `TCH005` would delete the
entire `if` statement.

The fix in this PR is to not consider it a violation if there are any
`elif`/`else` blocks. This also matches the behavior of the original
plugin.

fixes: #11368 

## Test plan

Add test cases.
2024-05-12 20:22:25 -04:00
Jane Lewis d7f093ef9e
`ruff server`: Support `noqa` comment code action (#11276)
## Summary

Fixes https://github.com/astral-sh/ruff/issues/10594.

Code actions to disable a diagnostic via `noqa` comment are now
available.


https://github.com/astral-sh/ruff/assets/19577865/6d3bcf11-a9d9-499b-8c7f-a10cd39cfbba

`DiagnosticFix` has been changed so that `noqa` code actions appear even
for diagnostics with no available quick fix. It can contain quick fix
edits, `noqa` comment edits, or both.

## Test Plan

The scenarios that need to be tested are as follows:
* A code action to disable a diagnostic should be available for every
diagnostic.
* Using this code action should append to the appropriate line with the
diagnostic, or modify an existing `noqa` comment.
* Adding a `noqa` comment manually should make a diagnostic disappear
* `Fix all auto-fixable problems` should not add `noqa` comments
* Removing a code from a `noqa` comment should make the diagnostic
re-appear
2024-05-12 14:39:46 -07:00
Charlie Marsh 4b330b11c6
[`flake8-pie`] Preserve parentheses in `unnecessary-dict-kwargs` (#11372)
## Summary

Closes https://github.com/astral-sh/ruff/issues/11371.
2024-05-11 18:04:54 -04:00
Jane Lewis 890cc325d5
Split `add_noqa` process into distinctive edit generation and edit application stages (#11265)
## Summary

`--add-noqa` now runs in two stages: first, the linter finds all
diagnostics that need noqa comments and generate edits on a per-line
basis. Second, these edits are applied, in order, to the document.

A public-facing function, `generate_noqa_edits`, has also been
introduced, which returns noqa edits generated on a per-diagnostic
basis. This will be used by `ruff server` for noqa comment quick-fixes.

## Test Plan

Unit tests have been updated.
2024-05-10 23:16:52 +00:00
Douglas Thor 0726e82342
[pyflakes] Update docs to describe WAI behavior (F541) (#11362)
Addresses this comment:
https://github.com/astral-sh/ruff/issues/11357#issuecomment-2104714029


## Summary

The docs for F541 did not mention some surprising, but WAI, behavior
regarding implicit string concatenation. Update the docs to describe the
behavior.

Here's how things rendered for me locally:


![image](https://github.com/astral-sh/ruff/assets/5386897/32067121-b190-4268-b987-ff37df11a618)
2024-05-10 19:10:34 +00:00
Dhruv Manilawala f79c980e17
Add support for attribute docstring in the semantic model (#11315)
## Summary

This PR adds updates the semantic model to detect attribute docstring.

Refer to [PEP 258](https://peps.python.org/pep-0258/#attribute-docstrings) 
for the definition of an attribute docstring.

This PR doesn't add full support for it but only considers string
literals as attribute docstring for the following cases:
1. A string literal following an assignment statement in the **global
scope**.
2. A global class attribute

For an assignment statement, it's considered an attribute docstring only
if the target expression is a name expression (`x = 1`). So, chained
assignment, multiple assignment or unpacking, and starred expression,
which are all valid in the target position, aren't considered here.

In `__init__` method, an assignment to the `self` variable like `self.x = 1`
is also a candidate for an attribute docstring. **This PR does not
support this position.**

## Test Plan

I used the following source code along with a print statement to verify
that the attribute docstring detection is correct.

Refer to the PR description for the code snippet.

I'll add this in the follow-up PR
(https://github.com/astral-sh/ruff/pull/11302) which uses this method.
2024-05-10 20:27:56 +05:30
Charlie Marsh 35ba3c91ce
Use `u64` instead of `i64` in Int type (#11356)
## Summary

I believe the value here is always unsigned, since we represent `-42` as
a unary operator on `42`.
2024-05-10 13:35:15 +00:00
Alex Waygood 3e8878a1c8
Bump version to v0.4.4 (#11352) 2024-05-09 17:00:46 +00:00
Carl Meyer b6b4ad9949
[red-knot] @override lint rule (#11282)
## Summary

Lots of TODOs and things to clean up here, but it demonstrates the
working lint rule.

## Test Plan

```
➜ cat main.py
from typing import override
from base import B

class C(B):
    @override
    def method(self): pass

➜ cat base.py
class B: pass

➜ cat typing.py
def override(func):
    return func
```

(We provide our own `typing.py` since we don't have typeshed vendored or
type stub support yet.)

```
➜ ./target/debug/red_knot main.py
...
1   0.012086s TRACE red_knot Main Loop: Tick
[crates/red_knot/src/main.rs:157:21] diagnostics = [
    "Method C.method is decorated with `typing.override` but does not override any base class method",
]
```

If we add `def method(self): pass` to class `B` in `base.py` and run
red_knot again, there is no lint error.

---------

Co-authored-by: Micha Reiser <micha@reiser.io>
2024-05-09 09:25:08 -06:00
Auguste Lalande dd42961dd9
[`pylint`] Detect `pathlib.Path.open` calls in `unspecified-encoding` (`PLW1514`) (#11288)
<!--
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

Resolves #11263

Detect `pathlib.Path.open` calls which do not specify a file encoding.

## Test Plan

Test cases added to fixture.

---------

Co-authored-by: Dhruv Manilawala <dhruvmanila@gmail.com>
2024-05-09 12:36:20 +00:00
Alex Waygood c80c1712f0
[red-knot] Vendor typeshed's stdlib (#11340)
This PR vendors typeshed!

-  The first commit vendors the stdlib directory from typeshed into a new crates/red_knot/vendored_typeshed directory.
-  The second commit adjusts various linting config files to make sure that the vendored code is excluded from typo checks, formatting checks, etc.
-  The LICENSE and README.md files are also vendored, but all other directories and files (stubs, scripts, tests, test_cases, etc.) are excluded. We should have no need for them (except possibly stubs/, discussed in more depth below).
-  Similar to the way pyright has a commit.txt file in its vendored copy of typeshed, to indicate which typeshed commit the vendored code corresponds to, I've also added a crates/red_knot/vendored_typeshed/source_commit.txt file in the third commit of this PR.

One open question is: should we vendor the stdlib and stubs directories, or just the stdlib directory? The stubs/ directory contains stubs for 162 third-party packages outside the stdlib. Mypy and typeshed_client1 only vendor the stdlib directory; pyright and pyre vendor both the stdlib and stubs directories; pytype vendors the entire typeshed repo (scripts/, tests/ and all).

In this PR, I've chosen to copy mypy and typeshed_client. Unlike vendoring the stdlib, which is unavoidable if we want to do typechecking of the stdlib, it's not strictly necessary to vendor the stubs directory: each subdirectory in stubs is published to PyPI as a standalone stubs distribution that can be (uv)-pip-installed into a virtual environment. It might be useful for our users if we vendored those stubs anyway, but there are costs as well as benefits to doing so (apart from just the sheer amount of vendored code in the ruff repository), so I'd rather consider it separately.
2024-05-09 12:44:53 +01:00
Charlie Marsh e2fe177c6b
Revert "Simplify arithmetic operation in logical lines checker (#11346)" (#11348)
## Summary

I merged this, but I think it might not be the same behavior? See my
comment at:
https://github.com/astral-sh/ruff/pull/11346#discussion_r1594848224
2024-05-08 21:51:37 -04:00
Auguste Lalande e9d1cddc97
Simplify arithmetic operation in logical lines checker (#11346)
## Summary

Simplify arithmetic operation in logical lines checker
2024-05-08 20:59:56 -04:00
Alex Waygood dfe4291c0b
Improve `ruff_python_semantic::all::extract_all_names()` (#11335) 2024-05-08 17:09:31 +01:00
Micha Reiser 4541337f3d
[red-knot] Remove `<Db: SemanticDb>` contraints in favor of dynamic dispatch (#11339) 2024-05-08 18:07:14 +02:00
Charlie Marsh 8e9ddee392
Ignore end-of-line comments when determining blank line rules (#11342)
## Summary

Closes https://github.com/astral-sh/ruff/issues/11331.
2024-05-08 15:19:27 +00:00
Charlie Marsh 702d2fa1eb
Make B024 and B027 documentation more nuanced (#11341)
Closes https://github.com/astral-sh/ruff/issues/11334.
2024-05-08 11:16:58 -04:00
Carl Meyer caf01472d5
[red-knot] fix re-hashing in Files and SymbolTable (#11327) 2024-05-08 06:31:19 -06:00
Micha Reiser 22639c5a2a
Move all module from the AST to the semantic crate (#11330) 2024-05-08 08:56:50 +00:00
Ahmed Ilyas 8591adba11
Consider with statements for too many branches lint (#11321)
Resolves https://github.com/astral-sh/ruff/issues/11313

## Summary

PLR0912(too-many-branches) did not count branches inside with: blocks.
With this fix, the branches inside with statements are also counted.

## Test Plan

Added a new test case.
2024-05-08 03:10:12 +00:00
Tushar Sadhwani 56b4c47d74
[`flake8-pyi`] Implement `PYI062` (`duplicate-literal-member`) (#11269) 2024-05-07 19:28:06 +01:00
Alex Waygood 6774f27f4b
Refactor the `ExprDict` node (#11267)
Co-authored-by: Micha Reiser <micha@reiser.io>
2024-05-07 11:46:10 +00:00
Abdur-Rahmaan Janhangeer de270154a1
chore(comment): Define HIR (#11320) 2024-05-07 12:39:55 +02:00
Tushar Sadhwani bc3f4fa3bc
[`flake8-pyi`] Implement `PYI059` (`generic-not-last-base-class`) (#11233) 2024-05-07 10:07:56 +00:00
Dhruv Manilawala 28cc71fb6b
Remove cyclic dev dependency with the parser crate (#11261)
## Summary

This PR removes the cyclic dev dependency some of the crates had with
the parser crate.

The cyclic dependencies are:
* `ruff_python_ast` has a **dev dependency** on `ruff_python_parser` and
`ruff_python_parser` directly depends on `ruff_python_ast`
* `ruff_python_trivia` has a **dev dependency** on `ruff_python_parser`
and `ruff_python_parser` has an indirect dependency on
`ruff_python_trivia` (`ruff_python_parser` - `ruff_python_ast` -
`ruff_python_trivia`)

Specifically, this PR does the following:
* Introduce two new crates
* `ruff_python_ast_integration_tests` and move the tests from the
`ruff_python_ast` crate which uses the parser in this crate
* `ruff_python_trivia_integration_tests` and move the tests from the
`ruff_python_trivia` crate which uses the parser in this crate

### Motivation

The main motivation for this PR is to help development. Before this PR,
`rust-analyzer` wouldn't provide any intellisense in the
`ruff_python_parser` crate regarding the symbols in `ruff_python_ast`
crate.

```
[ERROR][2024-05-03 13:47:06] .../vim/lsp/rpc.lua:770	"rpc"	"/Users/dhruv/.cargo/bin/rust-analyzer"	"stderr"	"[ERROR project_model::workspace] cyclic deps: ruff_python_parser(Idx::<CrateData>(50)) -> ruff_python_ast(Idx::<CrateData>(37)), alternative path: ruff_python_ast(Idx::<CrateData>(37)) -> ruff_python_parser(Idx::<CrateData>(50))\n"
```

## Test Plan

Check the logs of `rust-analyzer` to not see any signs of cyclic
dependency.
2024-05-07 09:24:57 +00:00
Charlie Marsh 12b5c3a54c
[`flake8-bugbear`] Ignore enum classes in `cached-instance-method` (`B019`) (#11312)
## Summary

While I was here, I also updated the rule to use
`function_type::classify` rather than hard-coding `staticmethod` and
friends.

Per Carl:

> Enum instances are already referred to by the class, forming a cycle
that won't get collected until the class itself does. At which point the
`lru_cache` itself would be collected, too.

Closes https://github.com/astral-sh/ruff/issues/9912.
2024-05-06 14:19:22 -04:00
Charlie Marsh a73b8c82a8
Add globbing to isort sections docs (#11311)
Closes https://github.com/astral-sh/ruff/issues/11310.
2024-05-06 18:12:29 +00:00
Abdur-Rahmaan Janhangeer 2f1983e4ad
fix typo (#11309) 2024-05-06 12:04:53 -04:00
Micha Reiser 868bbd4de6
Fix 'MarkVerbatimCommentsAsFormattedVisitor' is unused warning in release builds (#11304) 2024-05-06 07:43:16 +00:00
Charlie Marsh 1bb61bab67
Respect logged and re-raised expressions in nested statements (#11301)
## Summary

Historically, we only ignored `flake8-blind-except` if you re-raised or
logged the exception as a _direct_ child statement; but it could be
nested somewhere. This was just a known limitation at the time of adding
the previous logic.

Closes https://github.com/astral-sh/ruff/issues/11289.
2024-05-05 21:52:09 -04:00
Charlie Marsh 9db11dcce2
Touch-up error messages in server file discovery (#11285)
## Summary

Just making these messages a little more consistent with how we format
them in Ruff, uv, etc.
2024-05-05 13:20:51 -04:00
Jane Lewis a8a97291d1
Fix `ruff server` hanging after Neovim closes (#11291)
## Summary

A follow-up to https://github.com/astral-sh/ruff/pull/11222. `ruff
server` stalls during shutdown with Neovim because after it receives an
exit notification and closes the I/O thread, it attempts to log a
success message to `stderr`. Removing this log statement fixes this
issue.

## Test Plan

Track the instances of `ruff` in the OS task manager as you open and
close Neovim. A new instance should appear when Neovim starts and it
should disappear once Neovim is closed.
2024-05-05 17:15:48 +00:00
Charlie Marsh c3e0306c9d
Allow `set(True)` for boolean traps (#11287)
Closes https://github.com/astral-sh/ruff/issues/8923.
2024-05-04 21:33:08 +00:00
Jane Lewis 1d20422ba9
Create snapshot tests for `--add-noqa` (#11286) 2024-05-04 18:02:46 +00:00
Jane Lewis c4bf783b85
`ruff server`: Editor settings are used by default if no file-based configuration exists (#11266)
## Summary

Fixes https://github.com/astral-sh/ruff/issues/11258.

This PR fixes the settings resolver to match the expected behavior when
file-based configuration is not available.

## Test Plan

In a workspace with no file-based configuration, set a setting in your
editor and confirm that this setting is used instead of the default.
2024-05-04 10:52:01 -07:00
Charlie Marsh 6587dc1269
Use shared `is_stub` in unused argument rules (#11284)
## Summary

We already have a shared helper for this.
2024-05-04 13:51:44 -04:00
Charlie Marsh 9d45987c19
Expand tildes when resolving Ruff server configuration file (#11283)
## Summary

Users can now include tildes and environment variables in the provided
path, just like with `--config`.

Closes #11277.

## Test Plan

Set the configuration path to `"ruff.configuration": "~/x.toml"`;
verified that the server attempted to read from `/Users/crmarsh/x.toml`.

![Screenshot 2024-05-04 at 1 31
43 PM](https://github.com/astral-sh/ruff/assets/1309177/ea9829cd-6d8a-4818-a47c-dcff9219e996)
2024-05-04 13:51:26 -04:00
Carlos Cabral 5f0c189fa1
Change `hardcoded-tmp-directory-extend` example to follow the schema (#11275)
## Summary
Change `hardcoded-tmp-directory-extend` example to follow the schema:

1e91a09918/ruff.schema.json (L896-L901)
<!-- What's the purpose of the change? What does it do, and why? -->
2024-05-03 20:44:38 -05:00
Charlie Marsh 1e91a09918
Bump version to v0.4.3 (#11274) 2024-05-03 18:48:31 -04:00
Charlie Marsh d0f51c6434
Remove remaining `ruff_shrinking` references (#11272)
## Summary

This caused `rooster release` to fail.

Initially removed in https://github.com/astral-sh/ruff/pull/11242.
2024-05-03 20:22:08 +00:00
Charlie Marsh 8dd38110d9
Use function range for `reimplemented-operator` diagnostics (#11271) 2024-05-03 20:11:02 +00:00
Charlie Marsh 894cd13ec1
[`refurb`] Ignore methods in `reimplemented-operator` (`FURB118`) (#11270)
## Summary

This rule does more harm than good when applied to methods.

Closes https://github.com/astral-sh/ruff/issues/10898.

Closes https://github.com/astral-sh/ruff/issues/11045.
2024-05-03 20:03:12 +00:00
Tushar Sadhwani f3284fde9a
Remove unnecessary check for RUF020 enabled (#11268)
## Summary

In #9218 `Rule::NeverUnion` was partially removed from a
`checker.any_enabled` call. This makes the change consistent.

## Test Plan

`cargo test`
2024-05-03 18:19:13 +00:00
Carl Meyer 82dd5e6936
[red-knot] resolve class members (#11256) 2024-05-03 11:34:13 -06:00
Micha Reiser 6a1e555537
Upgrade to Rust 1.78 (#11260) 2024-05-03 12:46:21 +00:00
Charlie Marsh 349a4cf8ce
Remove trailing reference section (#11257) 2024-05-03 01:23:40 +00:00
Jane Lewis dfbeca5bdd
`ruff server` no longer hangs after shutdown (#11222)
## Summary

Fixes https://github.com/astral-sh/ruff/issues/11207.

The server would hang after handling a shutdown request on
`IoThreads::join()` because a global sender (`MESSENGER`, used to send
`window/showMessage` notifications) would remain allocated even after
the event loop finished, which kept the writer I/O thread channel open.

To fix this, I've made a few structural changes to `ruff server`. I've
wrapped the send/receive channels and thread join handle behind a new
struct, `Connection`, which facilitates message sending and receiving,
and also runs `IoThreads::join()` after the event loop finishes. To
control the number of sender channels, the `Connection` wraps the sender
channel in an `Arc` and only allows the creation of a wrapper type,
`ClientSender`, which hold a weak reference to this `Arc` instead of
direct channel access. The wrapper type implements the channel methods
directly to prevent access to the inner channel (which would allow the
channel to be cloned). ClientSender's function is analogous to
[`WeakSender` in
`tokio`](https://docs.rs/tokio/latest/tokio/sync/mpsc/struct.WeakSender.html).
Additionally, the receiver channel cannot be accessed directly - the
`Connection` only exposes an iterator over it.

These changes will guarantee that all channels are closed before the I/O
threads are joined.

## Test Plan

Repeatedly open and close an editor utilizing `ruff server` while
observing the task monitor. The net total amount of open `ruff`
instances should be zero once all editor windows have closed.

The following logs should also appear after the server is shut down:

<img width="835" alt="Screenshot 2024-04-30 at 3 56 22 PM"
src="https://github.com/astral-sh/ruff/assets/19577865/404b74f5-ef08-4bb4-9fa2-72e72b946695">

This can be tested on VS Code by changing the settings and then checking
`Output`.
2024-05-03 01:09:42 +00:00
Charlie Marsh 9e69cd6e93
Rephrase rationale for `pytest-incorrect-pytest-import` (#11255)
## Summary

Closes https://github.com/astral-sh/ruff/issues/11247.
2024-05-03 00:51:42 +00:00
plredmond b90a937a59
Add decorator types to function type (#11253)
* Add `decorators: Vec<Type>` to `FunctionType` struct
* Thread decorators through two `add_function` definitions
* Populate decorators at the callsite in `infer_symbol_type`
* Small test
2024-05-02 16:58:56 -07:00
plredmond 59afff0e6a
F401 - Distinguish between imports we wish to remove and those we wish to make explicit-exports (#11168)
Resolves #10390 and starts to address #10391

# Changes to behavior

* In `__init__.py` we now offer some fixes for unused imports.
* If the import binding is first-party this PR suggests a fix to turn it
into a redundant alias.
* If the import binding is not first-party, this PR suggests a fix to
remove it from the `__init__.py`.
* The fix-titles are specific to these new suggested fixes.
* `checker.settings.ignore_init_module_imports` setting is
deprecated/ignored. There is probably a documentation change to make
that complete which I haven't done.

---

<details><summary>Old description of implementation changes</summary>

# Changes to the implementation

* In the body of the loop over import statements that contain unused
bindings, the bindings are partitioned into `to_reexport` and
`to_remove` (according to how we want to resolve the fact they're
unused) with the following predicate:
  ```rust
in_init && is_first_party(checker, &import.qualified_name().to_string())
// true means make it a reexport
  ```
* Instead of generating a single fix per import statement, we now
generate up to two fixes per import statement:
  ```rust
  (fix_by_removing_imports(checker, node_id, &to_remove, in_init).ok(),
   fix_by_reexporting(checker, node_id, &to_reexport, dunder_all).ok())
  ```
* The `to_remove` fixes are unsafe when `in_init`.
* The `to_explicit` fixes are safe. Currently, until a future PR, we
make them redundant aliases (e.g. `import a` would become `import a as
a`).

## Other changes

* `checker.settings.ignore_init_module_imports` is deprecated/ignored.
Instead, all fixes are gated on `checker.settings.preview.is_enabled()`.
* Got rid of the pattern match on the import-binding bound by the inner
loop because it seemed less readable than referencing fields on the
binding.
* [x] `// FIXME: rename "imports" to "bindings"` if reviewer agrees (see
code)
* [x] `// FIXME: rename "node_id" to "import_statement"` if reviewer
agrees (see code)

<details>
<summary><h2>Scope cut until a future PR</h2></summary>

* (Not implemented) The `to_explicit` fixes will be added to `__all__`
unless it doesn't exist. When `__all__` doesn't exist they're resolved
by converting to redundant aliases (e.g. `import a` would become `import
a as a`).
 
---

</details>

# Test plan

* [x] `crates/ruff_linter/resources/test/fixtures/pyflakes/F401_24`
contains an `__init__.py` with*out* `__all__` that exercises the
features in this PR, but it doesn't pass.
* [x]
`crates/ruff_linter/resources/test/fixtures/pyflakes/F401_25_dunder_all`
contains an `__init__.py` *with* `__all__` that exercises the features
in this PR, but it doesn't pass.
* [x] Write unit tests for the new edit functions in
`fix::edits::make_redundant_alias`.

</details>

---------

Co-authored-by: Micha Reiser <micha@reiser.io>
2024-05-02 16:10:32 -07:00
Micha Reiser 7cec3b2623
Remove num-cpus dependency (#11240) 2024-05-02 22:30:48 +02:00
Charlie Marsh 9a1f6f6762
Avoid allocations for isort module names (#11251)
## Summary

Random refactor I noticed when investigating the F401 changes. We don't
need to allocate in most cases here.
2024-05-02 19:17:56 +00:00
Charlie Marsh 3a7c01b365
Ignore list-copy recommendations for async `for` loops (#11250)
## Summary

Removes these from `PERF402`, but adds them to `PERF401`, with a custom
message to use an `async` comprehension.

Closes https://github.com/astral-sh/ruff/issues/10787.
2024-05-02 11:48:52 -07:00
Micha Reiser 64700d296f
Remove ImportMap (#11234)
## Summary

This PR removes the `ImportMap` implementation and all its routing
through ruff.

The import map was added in https://github.com/astral-sh/ruff/pull/3243
but we then never ended up using it to do cross file analysis.

We are now working on adding multifile analysis to ruff, and revisit
import resolution as part of it.


```
hyperfine --warmup 10 --runs 20 --setup "./target/release/ruff clean" \
              "./target/release/ruff check crates/ruff_linter/resources/test/cpython -e -s --extend-select=I" \
              "./target/release/ruff-import check crates/ruff_linter/resources/test/cpython -e -s --extend-select=I" 
Benchmark 1: ./target/release/ruff check crates/ruff_linter/resources/test/cpython -e -s --extend-select=I
  Time (mean ± σ):      37.6 ms ±   0.9 ms    [User: 52.2 ms, System: 63.7 ms]
  Range (min … max):    35.8 ms …  39.8 ms    20 runs
 
Benchmark 2: ./target/release/ruff-import check crates/ruff_linter/resources/test/cpython -e -s --extend-select=I
  Time (mean ± σ):      36.0 ms ±   0.7 ms    [User: 50.3 ms, System: 58.4 ms]
  Range (min … max):    34.5 ms …  37.6 ms    20 runs
 
Summary
  ./target/release/ruff-import check crates/ruff_linter/resources/test/cpython -e -s --extend-select=I ran
    1.04 ± 0.03 times faster than ./target/release/ruff check crates/ruff_linter/resources/test/cpython -e -s --extend-select=I
```

I suspect that the performance improvement should even be more
significant for users that otherwise don't have any diagnostics.


```
hyperfine --warmup 10 --runs 20 --setup "cd ../ecosystem/airflow && ../../ruff/target/release/ruff clean" \
              "./target/release/ruff check ../ecosystem/airflow -e -s --extend-select=I" \
              "./target/release/ruff-import check ../ecosystem/airflow -e -s --extend-select=I" 
Benchmark 1: ./target/release/ruff check ../ecosystem/airflow -e -s --extend-select=I
  Time (mean ± σ):      53.7 ms ±   1.8 ms    [User: 68.4 ms, System: 63.0 ms]
  Range (min … max):    51.1 ms …  58.7 ms    20 runs
 
Benchmark 2: ./target/release/ruff-import check ../ecosystem/airflow -e -s --extend-select=I
  Time (mean ± σ):      50.8 ms ±   1.4 ms    [User: 50.7 ms, System: 60.9 ms]
  Range (min … max):    48.5 ms …  55.3 ms    20 runs
 
Summary
  ./target/release/ruff-import check ../ecosystem/airflow -e -s --extend-select=I ran
    1.06 ± 0.05 times faster than ./target/release/ruff check ../ecosystem/airflow -e -s --extend-select=I

```

## Test Plan

`cargo test`
2024-05-02 11:26:02 -07:00
Charlie Marsh e62fa4ea32
Avoid debug assertion around NFKC renames (#11249)
## Summary

This assertion isn't quite correct, since with NFKC normalization, two
identifiers can have different lengths but map to the same binding.

Closes https://github.com/astral-sh/ruff/issues/11238.

Closes https://github.com/astral-sh/ruff/issues/11239.
2024-05-02 10:59:39 -07:00
Micha Reiser 1673bc466b
Remove ruff-shrinking crate (#11242) 2024-05-02 10:17:55 +02:00
Micha Reiser a70808b125
Make libc a platform specific dependency (#11241) 2024-05-02 07:45:08 +00:00
Jane Lewis 4aac1d1db9
`ruff server` respects `per-file-ignores` configuration (#11224)
## Summary

Fixes #11185
Fixes #11214 

Document path and package information is now forwarded to the Ruff
linter, which allows `per-file-ignores` to correctly match against the
file name. This also fixes an issue where the import sorting rule didn't
distinguish between third-party and first-party packages since we didn't
pass in the package root.

## Test Plan

`per-file-ignores` should ignore files as expected. One quick way to
check is by adding this to your `pyproject.toml`:
```toml
[tool.ruff.lint.per-file-ignores]
"__init__.py" = ["ALL"]
```

Then, confirm that no diagnostics appear when you add code to an
`__init__.py` file (besides syntax errors).

The import sorting fix can be verified by failing to reproduce the
original issue - an `I001` diagnostic should not appear in
`other_module.py`.
2024-05-01 19:24:35 -07:00
Dhruv Manilawala 653c8d83e9
Rename variable to `indent_width` to match docs (#11230)
Reference:
https://github.com/astral-sh/ruff/issues/8705#issuecomment-2084726911
2024-05-01 12:04:03 +00:00
Micha Reiser 376fb71a7f
Avoid parsing the root configuration twice (#10625) 2024-05-01 09:28:30 +00:00
Jane Lewis 068e22d382
`ruff server` reads from a configuration TOML file in the user configuration directory if no local configuration exists (#11225)
## Summary

Fixes https://github.com/astral-sh/ruff/issues/11158.

A settings file in the ruff user configuration directory will be used as
a configuration fallback, if it exists.

## Test Plan

Create a `pyproject.toml` or `ruff.toml` configuration file in the ruff
user configuration directory.

* On Linux, that will be `$XDG_CONFIG_HOME/ruff/` or `$HOME/.config`
* On macOS, that will be `$HOME/Library/Application Support`
* On Windows, that will be `{FOLDERID_LocalAppData}`

Then, open a file inside of a workspace with no configuration. The
settings in the user configuration file should be used.
2024-05-01 02:08:50 -07:00
Micha Reiser 1f217d54d0
[red-knot] Remove `Clone` from `Files` (#11213) 2024-05-01 09:11:39 +02:00
Charlie Marsh 414990c022
Respect `async` expressions in comprehension bodies (#11219)
## Summary

We weren't recursing into the comprehension body.
2024-04-30 18:38:31 +00:00
Jane Lewis 4779dd1173
Write `ruff server` setup guide for Helix (#11183)
## Summary

Closes #11027.
2024-04-30 10:15:29 -07:00
Charlie Marsh c5adbf17da
Ignore non-abstract class attributes when enforcing B024 (#11210)
## Summary

I think the check included here does make sense, but I don't see why we
would allow it if a value is provided for the attribute -- since, in
that case, isn't it _not_ abstract?

Closes: https://github.com/astral-sh/ruff/issues/11208.
2024-04-30 09:01:08 -07:00
Micha Reiser c6dcf3502b
[red-knot] Use `FileId` in module resolver to map from file to module (#11212) 2024-04-30 14:09:47 +00:00
Micha Reiser 1e585b8667
[red knot] Introduce `LintDb` (#11204) 2024-04-30 16:01:46 +02:00
Alex Waygood 21d824abfd
[`pylint`] Also emit `PLR0206` for properties with variadic parameters (#11200) 2024-04-30 11:59:37 +01:00
Micha Reiser 7e28c80354
[red-knot] Refactor `program.check` scheduling (#11202) 2024-04-30 07:23:41 +00:00
Micha Reiser bc03d376e8
[red-knot] Add "cheap" `program.snapshot` (#11172) 2024-04-30 07:13:26 +00:00
Alex Waygood eb6f562419
`red-knot`: introduce a `StatisticsRecorder` trait for the `KeyValueCache` (#11179)
## Summary

This PR changes the `DebugStatistics` and `ReleaseStatistics` structs so
that they implement a common `StatisticsRecorder` trait, and makes the
`KeyValueCache` struct generic over a type parameter bound to that
trait. The advantage of this approach is that it's much harder for the
`DebugStatistics` and `ReleaseStatistics` structs to accidentally grow
out of sync in the methods that they implement, which was the cause of
the release-build failure recently fixed in #11177.

## Test Plan

`cargo test -p red_knot` and `cargo build --release` both continue to
pass for me locally
2024-04-30 07:14:06 +01:00
Micha Reiser 5561d445d7
linter: Enable test-rules for test build (#11201) 2024-04-30 08:06:47 +02:00
plredmond c391c8b6cb
Red Knot - Add symbol flags (#11134)
* Adds `Symbol.flag` bitfield. Populates it from (the three renamed)
`add_or_update_symbol*` methods.
* Currently there are these flags supported:
  * `IS_DEFINED` is set in a scope where a variable is defined.
* `IS_USED` is set in a scope where a variable is referenced. (To have
both this and `IS_DEFINED` would require two separate appearances of a
variable in the same scope-- one def and one use.)
* `MARKED_GLOBAL` and `MARKED_NONLOCAL` are **not yet implemented**.
(*TODO: While traversing, if you find these declarations, add these
flags to the variable.*)
* Adds `Symbol.kind` field (commented) and the data structure which will
populate it: `Kind` which is an enum of freevar, cellvar,
implicit_global, and implicit_local. **Not yet populated**. (*TODO: a
second pass over the scope (or the ast?) will observe the
`MARKED_GLOBAL` and `MARKED_NONLOCAL` flags to populate this field. When
that's added, we'll uncomment the field.*)
* Adds a few tests that the `IS_DEFINED` and `IS_USED` fields are
correctly set and/or merged:
* Unit test that subsequent calls to `add_or_update_symbol` will merge
the flag arguments.
* Unit test that in the statement `x = foo`, the variable `foo` is
considered used but not defined.
* Unit test that in the statement `from bar import foo`, the variable
`foo` is considered defined but not used.

---------

Co-authored-by: Carl Meyer <carl@astral.sh>
2024-04-29 17:07:23 -07:00
Carl Meyer ce030a467f
[red-knot] resolve base class types (#11178)
## Summary

Resolve base class types, as long as they are simple names.

## Test Plan

cargo test
2024-04-29 16:22:30 -06:00
Dhruv Manilawala 04a922866a
Add basic docs for the parser crate (#11199)
## Summary

This PR adds a basic README for the `ruff_python_parser` crate and
updates the CONTRIBUTING docs with the fuzzer and benchmark section.

Additionally, it also updates some inline documentation within the
parser crate and splits the `parse_program` function into
`parse_single_expression` and `parse_module` which will be called by
matching against the `Mode`.

This PR doesn't go into too much internal detail around the parser logic
due to the following reasons:
1. Where should the docs go? Should it be as a module docs in `lib.rs`
or in README?
2. The parser is still evolving and could include a lot of refactors
with the future work (feedback loop and improved error recovery and
resilience)

---------

Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
2024-04-29 17:08:07 +00:00
Alex Waygood 87929ad5f1
Add convenience methods for iterating over all parameter nodes in a function (#11174) 2024-04-29 10:36:15 +00:00
Micha Reiser 3474e37836
[red-knot] Unresolved imports lint rule (#11164) 2024-04-28 12:12:49 +02:00
Micha Reiser 00d7c01cfc
[red-knot] Fix absolute imports in `module.resolve_name` (#11180) 2024-04-27 20:07:07 +02:00
Micha Reiser 983a06cec3
[red-knot] Resolve and check dependencies (#11161) 2024-04-27 15:49:03 +00:00
Alex Waygood 47692027bf
Fix `cargo build --release` (#11177)
## Summary

`cargo build --release` currently fails to compile on `main`:

<details>

```
error[E0599]: no method named `hit` found for struct `ReleaseStatistics` in the current scope
   --> crates/red_knot/src/cache.rs:22:29
    |
22  |             self.statistics.hit();
    |                             ^^^ method not found in `ReleaseStatistics`
...
145 | pub struct ReleaseStatistics;
    | ---------------------------- method `hit` not found for this struct

error[E0599]: no method named `miss` found for struct `ReleaseStatistics` in the current scope
   --> crates/red_knot/src/cache.rs:25:29
    |
25  |             self.statistics.miss();
    |                             ^^^^ method not found in `ReleaseStatistics`
...
145 | pub struct ReleaseStatistics;
    | ---------------------------- method `miss` not found for this struct

error[E0599]: no method named `hit` found for struct `ReleaseStatistics` in the current scope
   --> crates/red_knot/src/cache.rs:36:33
    |
36  |                 self.statistics.hit();
    |                                 ^^^ method not found in `ReleaseStatistics`
...
145 | pub struct ReleaseStatistics;
    | ---------------------------- method `hit` not found for this struct

error[E0599]: no method named `miss` found for struct `ReleaseStatistics` in the current scope
   --> crates/red_knot/src/cache.rs:41:33
    |
41  |                 self.statistics.miss();
    |                                 ^^^^ method not found in `ReleaseStatistics`
...
145 | pub struct ReleaseStatistics;
    | ---------------------------- method `miss` not found for this struct
```

</details>

This is because in a release build, `CacheStatistics` is a type alias
for `ReleaseStatistics`, and `ReleaseStatistics` doesn't have `hit()` or
`miss()` methods. (In a debug build, `CacheStatistics` is a type alias
for `DebugStatistics`, which _does_ have those methods.)

Possibly we could make this less likely to happen in the future by
making both structs implement a common trait instead of using type
aliases that vary depending on whether it's a debug build or not? For
now, though, this PR just brings the two structs in sync w.r.t. the
methods they expose.

## Test Plan

`cargo build --release` now once again compiles for me locally
2024-04-27 11:45:32 -04:00
Charlie Marsh ec3243a6e5
Prioritize `redefined-while-unused` over `unused-import` (#11173)
## Summary

This PR adds an override to the fixer to ensure that we apply any
`redefined-while-unused` fixes prior to `unused-import`.

Closes https://github.com/astral-sh/ruff/issues/10905.
2024-04-27 11:44:53 -04:00
Carl Meyer 2d6978f236
[red-knot] fix class vs instance (#11175)
## Summary

Clarify the type of an exact class object vs the type of instances of
that class.

## Test Plan

cargo test
2024-04-27 09:09:02 -06:00
Auguste Lalande 2490d2d4af
[`ruff`] Detect duplicate codes as part of `unused-noqa` (`RUF100`) (#10850)
## Summary

Implement duplicate code detection as part of `RUF100`, mirroring the
behavior of `flake8-noqa` (`NQA005`) mentioned in #850. The idea to
merge the rule into `RUF100` was suggested by @MichaReiser
https://github.com/astral-sh/ruff/pull/10325#issuecomment-2025535444.

## Test Plan

Test cases were added to the fixture.
2024-04-27 12:33:44 +00:00
Jelle Zijlstra 59b73fabc1
[`pyflakes`] Improve `invalid-print-syntax` documentation (#11171)
This syntax wasn't "deprecated" in Python 3; it was removed.

I started looking at this rule because I was curious how Ruff could even
detect this without a Python 2 parser. Then I realized that
"print >> f, x" is actually valid Python 3 syntax: it creates a tuple
containing a right-shifted version of the print function.
2024-04-27 07:54:04 -04:00
Micha Reiser 61c97a037c
red-knot: Introduce `program.check` (#11148) 2024-04-27 09:01:20 +00:00
Micha Reiser 7cd065e4a2
Kick off Red-knot (#10849)
Co-authored-by: Carl Meyer <carl@oddbird.net>
Co-authored-by: Carl Meyer <carl@astral.sh>
2024-04-27 08:34:00 +00:00
Carl Meyer 845ba7cf5f
Make ImportFrom level just a u32 (#11170) 2024-04-26 20:38:35 -06:00
Auguste Lalande 5994414739
[`ruff`] Implement `redirected-noqa` (`RUF101`) (#11052)
## Summary

Based on discussion in #10850.

As it stands today `RUF100` will attempt to replace code redirects with
their target codes even though this is not the "goal" of `RUF100`. This
behavior is confusing and inconsistent, since code redirects which don't
otherwise violate `RUF100` will not be updated. The behavior is also
undocumented. Additionally, users who want to use `RUF100` but do not
want to update redirects have no way to opt out.

This PR explicitly detects redirects with a new rule `RUF101` and
patches `RUF100` to keep original codes in fixes and reporting.

## Test Plan

Added fixture.
2024-04-27 02:08:11 +00:00
Jane Lewis 632965d0fa
`ruff server`: Support a custom TOML configuration file (#11140)
## Summary

Closes #10985.

The server now supports a custom TOML configuration file as a client
setting. The setting must be an absolute path to a file. If the file is
called `pyproject.toml`, the server will attempt to parse it as a
pyproject file - otherwise, it will attempt to parse it as a `ruff.toml`
file, even if the file has a name besides `ruff.toml`.

If an option is set in both the custom TOML configuration file and in
the client settings directly, the latter will be used.

## Test Plan

1. Create a `ruff.toml` file outside of the workspace you are testing.
Set an option that is different from the one in the configuration for
your test workspace.
2. Set the path to the configuration in NeoVim:
```lua
require('lspconfig').ruff.setup {
    init_options = {
      settings = {
        configuration = "absolute/path/to/your/configuration"
      }
    }
}
```
3. Confirm that the option in the configuration file is used, regardless
of what the option is set to in the workspace configuration.
4. Add the same option, with a different value, to the NeoVim
configuration directly. For example:
```lua
require('lspconfig').ruff.setup {
    init_options = {
      settings = {
        configuration = "absolute/path/to/your/configuration",
        lint = {
          select = []
        }
      }
    }
}
```
5. Confirm that the option set in client settings is used, regardless of
the value in either the custom configuration file or in the workspace
configuration.
2024-04-26 23:46:07 +00:00
Dhruv Manilawala 77a72ecd38
Avoid multiline expression if format specifier is present (#11123)
## Summary

This PR fixes the bug where the formatter would format an f-string and
could potentially change the AST.

For a triple-quoted f-string, the element can't be formatted into
multiline if it has a format specifier because otherwise the newline
would be treated as part of the format specifier.

Given the following f-string:
```python
f"""aaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbb ccccccccccc {
    variable:.3f} ddddddddddddddd eeeeeeee"""
```

The formatter sees that the f-string is already multiline so it assumes
that it can contain line breaks i.e., broken into multiple lines. But,
in this specific case we can't format it as:

```python
f"""aaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbb ccccccccccc {
    variable:.3f
} ddddddddddddddd eeeeeeee"""
```
                     
Because the format specifier string would become ".3f\n", which is not
the original string (`.3f`).

If the original source code already contained a newline, they'll be
preserved. For example:
```python
f"""aaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbb ccccccccccc {
    variable:.3f
} ddddddddddddddd eeeeeeee"""
```

The above will be formatted as:
```py
f"""aaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbb ccccccccccc {variable:.3f
} ddddddddddddddd eeeeeeee"""
```

Note that the newline after `.3f` is part of the format specifier which
needs to be preserved.
The Python version is irrelevant in this case.

fixes: #10040 

## Test Plan

Add some test cases to verify this behavior.
2024-04-26 13:34:38 +00:00
Jane Lewis 16a1f3cbcc
`ruff server`: Support setting to prioritize project configuration over editor configuration (#11086)
## Summary

This is intended to address
https://github.com/astral-sh/ruff-vscode/issues/425, and is a follow-up
to https://github.com/astral-sh/ruff/pull/11062.

A new client setting is now supported by the server,
`prioritizeFileConfiguration`. This is a boolean setting (default:
`false`) that, if set to `true`, will instruct the configuration
resolver to prioritize file configuration (aka discovered TOML files)
over configuration passed in by the editor.

A corresponding extension PR has been opened, which makes this setting
available for VS Code:
https://github.com/astral-sh/ruff-vscode/pull/457.

## Test Plan

To test this with VS Code, you'll need to check out [the VS Code
PR](https://github.com/astral-sh/ruff-vscode/pull/457) that adds this
setting.

The test process is similar to
https://github.com/astral-sh/ruff/pull/11062, but in scenarios where the
editor configuration would take priority over file configuration, file
configuration should take priority.
2024-04-26 08:17:28 +00:00
Jelle Zijlstra cd3e319538
Add support for PEP 696 syntax (#11120) 2024-04-26 09:47:29 +02:00
Steve C c8c227dd5d
[`refurb`] Implement `fstring-number-format` (`FURB116`) (#10921)
## Summary

Adds `FURB116`

See #1348 

## Test Plan

`cargo test`
2024-04-26 01:15:33 +00:00
Charlie Marsh b15e9e6e05
Include inline instantiations when detecting loggers (#11154)
## Summary

Closes https://github.com/astral-sh/ruff/issues/11031.
2024-04-25 21:00:12 -04:00
Alex Waygood 269014a539
Delete unused methods from `Parameters` (#11150) 2024-04-25 22:11:24 +01:00
Auguste Lalande 3364ef957d
[`pygrep_hooks`] Fix `blanket-noqa` panic when last line has noqa with no newline (`PGH004`) (#11108)
## Summary

Resolves #11102

The error stems from these lines

f5c7a62aa6/crates/ruff_linter/src/noqa.rs (L697-L702)
I don't really understand the purpose of incrementing the last index,
but it makes the resulting range invalid for indexing into `contents`.

For now I just detect if the index is too high in `blanket_noqa` and
adjust it if necessary.

## Test Plan

Created fixture from issue example.
2024-04-25 14:39:38 -04:00
Jane Lewis 77c93fd63c
Bump version to 0.4.2 (#11151) 2024-04-25 17:31:38 +00:00
Dhruv Manilawala 1c9f5e3001
Display the AST even with syntax errors (#11147)
## Summary

This PR updates the playground to display the AST even if it contains a
syntax error. This could be useful for development and also to give a
quick preview of what error recovery looks like.

Note that not all recovery is correct but this allows us to iterate
quickly on what can be improved.

## Test Plan

Build the playground locally and test it.

<img width="1688" alt="Screenshot 2024-04-25 at 21 02 22"
src="https://github.com/astral-sh/ruff/assets/67177269/2b94934c-4f2c-4a9a-9693-3d8460ed9d0b">
2024-04-25 21:55:23 +05:30
Dhruv Manilawala 4738e19974
Remove unused lexical error types (#11145) 2024-04-25 15:24:16 +00:00
bersbersbers f428bd5052
Docs: mention `lint.typing-modules` in `TCH001`, `TCH002`, `TCH003` (#11144)
## Summary

Mention `lint.typing-modules` in `TCH001`, `TCH002`, `TCH003`; close
#11142.
2024-04-25 11:23:03 -04:00
Jane Lewis 4690890e9f
`ruff server`: In 'publish diagnostics' mode, document diagnostics are cleared properly when a file is closed (#11137)
## Summary

Fixes #11114. 

As part of the `onClose` handler, we publish an empty array of
diagnostics for the document being closed, similar to
[`ruff-lsp`](187d7790be/ruff_lsp/server.py (L459-L464)).
This prevent phantom diagnostics from lingering after a document is
closed. We'll only do this if the client doesn't support pull
diagnostics, because otherwise clearing diagnostics is their
responsibility.

## Test Plan

Diagnostics should no longer appear for a document in the Problems tab
after the document is closed.
2024-04-24 19:38:54 -07:00
Sid cee38f39df
[`flake8-blind-expect`] Allow raise from in `BLE001` (#11131)
## Summary

This allows `raise from` in BLE001.

```python
try:
    ...
except Exception as e:
    raise ValueError from e
```

Fixes #10806

## Test Plan

Test case added.
2024-04-24 11:56:11 -04:00
Alex Waygood e3fde28146
[`flake8-pyi`] Allow overloaded `__exit__` and `__aexit__` definitions (`PYI036`) (#11057) 2024-04-24 15:48:52 +00:00
Ibraheem Ahmed 1c8849f9a8
Use Matchit to Resolve Per-File Settings (#11111)
## Summary

Continuation of https://github.com/astral-sh/ruff/pull/9444.

> When the formatter is fully cached, it turns out we actually spend
meaningful time mapping from file to `Settings` (since we use a
hierarchical approach to settings). Using `matchit` rather than
`BTreeMap` improves fully-cached performance by anywhere from 2-5%
depending on the project, and since these are all implementation details
of `Resolver`, it's minimally invasive.

`matchit` supports escaping routing characters so this change should now
be fully compatible.

## Test Plan

On my machine I'm seeing a ~3% improvement with this change.

```
hyperfine --warmup 20 -i "./target/release/main format ../airflow" "./target/release/ruff format ../airflow"
Benchmark 1: ./target/release/main format ../airflow
  Time (mean ± σ):      58.1 ms ±   1.4 ms    [User: 63.1 ms, System: 66.5 ms]
  Range (min … max):    56.1 ms …  62.9 ms    49 runs
 
Benchmark 2: ./target/release/ruff format ../airflow
  Time (mean ± σ):      56.6 ms ±   1.5 ms    [User: 57.8 ms, System: 67.7 ms]
  Range (min … max):    54.1 ms …  63.0 ms    51 runs
 
Summary
  ./target/release/ruff format ../airflow ran
    1.03 ± 0.04 times faster than ./target/release/main format ../airflow
```
2024-04-24 10:25:46 -04:00
Alex Waygood 37af6e6147
[`flake8-pyi`] Allow simple assignments to `None` in enum class scopes (`PYI026`) (#11128) 2024-04-24 15:13:55 +01:00
Micha Reiser 92814fd99b
Use crossbeam-channel instead of crossbeam (#11129) 2024-04-24 13:56:55 +00:00
Charlie Marsh 51dec8d95b
[`flake8-simplify`] Avoid raising `SIM911` for non-`zip` attribute calls (#11126)
## Summary

The `matches!` macro here is slightly off and allows _all_ attribute
calls through.

Closes https://github.com/astral-sh/ruff/issues/11125.
2024-04-24 13:05:17 +00:00
Nolan 7c8c1c71a3
Implement hover menu support for ruff-server; Issue #10595 (#11096)
<!--
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

Add support for hover menu to ruff_server, as requested in
[10595](https://github.com/astral-sh/ruff/issues/10595).
Majority of new code is in hover.rs.
I reused the regex from ruff-lsp's implementation. Also reused the
format_rule_text function from ruff/src/commands/rule.rs
Added capability registration in server.rs, and added the handler to
api.rs.

## Test Plan

Tested in NVIM v0.10.0-dev-2582+g2a8cef6bd, configured with lspconfig
using the default options (other than cmd pointing to my test build,
with options "server" and "--preview"). OS: Ubuntu 24.04, kernel
6.8.0-22.

---------

Co-authored-by: Jane Lewis <me@jane.engineering>
2024-04-23 20:16:02 +00:00
Jane Lewis 35ca887e02
`ruff server`: Ruff configuration from client settings overrides project configuration (#11062)
## Summary

This is a follow-up to https://github.com/astral-sh/ruff/pull/10984 that
implements configuration resolution for editor configuration. By 'editor
configuration', I'm referring to the client settings that correspond to
Ruff configuration/options, like `preview`, `select`, and so on. These
will be combined with 'project configuration' (configuration taken from
project files such as `pyproject.toml`) to generate the final linter and
formatter settings used by `RuffSettings`. Editor configuration takes
priority over project configuration.

In a follow-up pull request, I'll implement a new client setting that
allows project configuration to override editor configuration, as per
[this issue](https://github.com/astral-sh/ruff-vscode/issues/425).

## Review guide

The first commit, e38966d8843becc7234fa7d46009c16af4ba41e9, is just
doing re-arrangement so that we can pass the right things to
`RuffSettings::resolve`. The actual resolution logic is in the second
commit, 0eec9ee75c10e5ec423bd9f5ce1764f4d7a5ad86. It might help to look
at these comments individually since the diff is rather messy.

## Test Plan

For the settings to show up in VS Code, you'll need to checkout this
branch: https://github.com/astral-sh/ruff-vscode/pull/456.

To test that the resolution for a specific setting works as expected,
run through the following scenarios, setting it in project and editor
configuration as needed:

| Set in project configuration? | Set in editor configuration? |
Expected Outcome |

|-------------------------------|--------------------------------------------------|------------------------------------------------------------------------------------------|
| No | No | The editor should behave as if the setting was set to its
default value. |
| Yes | No | The editor should behave as if the setting was set to the
value in project configuration. |
| No | Yes | The editor should behave as if the setting was set to the
value in editor configuration. |
| Yes | Yes (but distinctive from project configuration) | The editor
should behave as if the setting was set to the value in editor
configuration. |

An exception to this is `extendSelect`, which does not have an analog in
TOML configuration. Instead, you should verify that `extendSelect`
amends the `select` setting. If `select` is set in both editor and
project configuration, `extendSelect` will only append to the `select`
value in editor configuration, so make sure to un-set it there if you're
testing `extendSelect` with `select` in project configuration.
2024-04-23 11:19:17 -07:00
Dhruv Manilawala 38d2562f41
Refactor unary expression parsing (#11088)
## Summary

This PR refactors unary expression parsing with the following changes:
* Ability to get `OperatorPrecedence` from a unary operator (`UnaryOp`)
* Implement methods on `TokenKind`
	* Add `as_unary_operator` which returns an `Option<UnaryOp>`
* Add `as_unary_arithmetic_operator` which returns an `Option<UnaryOp>`
(used for pattern parsing)
* Rename `is_unary` to `is_unary_arithmetic_operator` (used in the
linter)

resolves: #10752 

## Test Plan

Verify that the existing test cases pass, no ecosystem changes, run the
Python based fuzzer on 3000 random inputs and run it on dozens of
open-source repositories.
2024-04-23 04:55:02 +00:00
Dhruv Manilawala 7eba967e16
Refactor binary expression parsing (#11073)
## Summary

This PR refactors the binary expression parsing in a way to make it
readable and easy to understand. It draws inspiration from the suggested
edits in the linked messages in #10752.

### Changes

* Ability to get the precedence of an operator
	* From a boolean operator (`BinOp`) to `OperatorPrecedence`
	* From a binary operator (`Operator`) to `OperatorPrecedence`
	* No comparison operator because all of them have the same precedence
* Implement methods on `TokenKind` to convert it to an appropriate
operator enum
	* Add `as_boolean_operator` which returns an `Option<BoolOp>`
	* Add `as_binary_operator` which returns an `Option<Operator>`
* No `as_comparison_operator` because it requires lookahead and I'm not
sure if `token.as_comparison_operator(peek)` is a good way to implement
it
* Introduce `BinaryLikeOperator`
	* Constructed from two tokens using the methods from the second point
* Add `precedence` method using the conversion methods mentioned in the
first point
* Make most of the functions in `TokenKind` private to the module
* Use `self` instead of `&self` for `TokenKind` 

fixes: #11072

## Test Plan

Refer #11088
2024-04-23 04:42:40 +00:00
Dhruv Manilawala 5b81b8368d
Make associativity a property of operator precedence (#11065)
## Summary

This PR does a few things but the main change is that is makes
associativity a property of operator precedence.

1. Rename `Precedence` -> `OperatorPrecedence`
2. Rename `parse_expression_with_precedence` ->
`parse_binary_expression_or_higher`
3. Move `current_binding_power` to `OperatorPrecedence::try_from_tokens`
[^1]
4. Add a `OperatorPrecedence::is_right_associative` method
5. Move from `increment_precedence` to using `<=` / `<` to check if the
parsing loop needs to stop [^2]

[^1]: Another alternative would be to have two separate methods to avoid
lookahead as it's required only for once case (`not in`). So,
`try_from_current_token(current).or_else(|| try_from_next_token(current,
peek))`
[^2]: This will allow us to easily make the refactors mentioned in
#10752

## Test Plan

Make sure the precedence parsing algorithm is still correct by running
the test suite, fuzz testing it and running it against a dozen or so
open-source repositories.
2024-04-23 04:28:46 +00:00
Dhruv Manilawala c30735d4a7
Add `ExpressionContext` for expression parsing (#11055)
## Summary

This PR adds a new `ExpressionContext` struct which is used in
expression parsing.

This solves the following problem:
1. Allowing starred expression with different precedence
2. Allowing yield expression in certain context
3. Remove ambiguity with `in` keyword when parsing a `for ... in`
statement

For context, (1) was solved by adding `parse_star_expression_list` and
`parse_star_expression_or_higher` in #10623, (2) was solved by by adding
`parse_yield_expression_or_else` in #10809, and (3) was fixed in #11009.
All of the mentioned functions have been removed in favor of the context
flags.

As mentioned in #11009, an ideal solution would be to implement an
expression context which is what this PR implements. This is passed
around as function parameter and the call stack is used to automatically
reset the context.

### Recovery

How should the parser recover if the target expression is invalid when
an expression can consume the `in` keyword?

1. Should the `in` keyword be part of the target expression?
2. Or, should the expression parsing stop as soon as `in` keyword is
encountered, no matter the expression?

For example:
```python
for yield x in y: ...

# Here, should this be parsed as
for (yield x) in (y): ...
# Or
for (yield x in y): ...
# where the `in iter` part is missing
```

Or, for binary expression parsing:
```python
for x or y in z: ...

# Should this be parsed as
for (x or y) in z: ...
# Or
for (x or y in z): ...
# where the `in iter` part is missing
```

This need not be solved now, but is very easy to change. For context
this PR does the following:
* For binary, comparison, and unary expressions, stop at `in`
* For lambda, yield expressions, consume the `in`

## Test Plan

1. Add test cases for the `for ... in` statement and verify the
snapshots
2. Make sure the existing test suite pass
3. Run the fuzzer for around 3000 generated source code
4. Run the updated logic on a dozen or so open source repositories
(codename "parser-checkouts")
2024-04-23 04:19:05 +00:00
Jane Lewis 62478c3070
`ruff server`: Support publish diagnostics as a fallback when pull diagnostics aren't supported (#11092)
## Summary

Fixes #11059 

Several major editors don't support [pull
diagnostics](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_pullDiagnostics),
a method of sending diagnostics to the client that was introduced in
version `0.3.17` of the specification. Until now, `ruff server` has only
used pull diagnostics, which resulted in diagnostics not being available
on Neovim and Helix, which don't support pull diagnostics yet (though
Neovim `10.0` will have support for this).

`ruff server` will now utilize the older method of sending diagnostics,
known as 'publish diagnostics', when pull diagnostics aren't supported
by the client. This involves re-linting a document every time it is
opened or modified, and then sending the diagnostics generated from that
lint to the client via the `textDocument/publishDiagnostics`
notification.

## Test Plan

The easiest way to test that this PR works is to check if diagnostics
show up on Neovim `<=0.9`.
2024-04-22 21:06:35 -07:00
Ottavio Hartman 111bbc61f6
[`refurb`] New rule to suggest min/max over sorted() (`FURB192`) (#10868)
## Summary

Fixes #10463

Add `FURB192` which detects violations like this:

```python
# Bad
a = sorted(l)[0]

# Good
a = min(l)
```

There is a caveat that @Skylion007 has pointed out, which is that
violations with `reverse=True` technically aren't compatible with this
change, in the edge case where the unstable behavior is intended. For
example:

```python
from operator import itemgetter
data = [('red', 1), ('blue', 1), ('red', 2), ('blue', 2)]

min(data, key=itemgetter(0))  # ('blue', 1)
sorted(data, key=itemgetter(0))[0]  # ('blue', 1)
sorted(data, key=itemgetter(0), reverse=True)[-1]  # ('blue, 2')
```

This seems like a rare edge case, but I can make the `reverse=True`
fixes unsafe if that's best.

## Test Plan

This is unit tested.

## References

https://github.com/dosisod/refurb/pull/333/files

---------

Co-authored-by: Charlie Marsh <charlie.r.marsh@gmail.com>
2024-04-23 01:13:57 +00:00
Charlie Marsh 925c7f8dd3
[`refurb`] Advoid `operator.itemgetter` suggestion for single-item tuple (#11095)
## Summary

The `operator.itemgetter` behavior changes where there's more than one
argument, such that `operator.itemgetter(0)` yields `r[0]`, rather than
`(r[0],)`.

Closes https://github.com/astral-sh/ruff/issues/11075.
2024-04-23 00:20:43 +00:00
KotlinIsland 5b4c8a7c5f
(📚) fix docs for `invalid-X-returns` (#11094)
## Summary

There is no class `integer` in python, nor is there a type `integer`, so
I updated the docs to remove the backticks on these references, such
that it is the representation of an integer, and not a reference.
2024-04-23 00:17:47 +00:00
Auguste Lalande 647548b5e7
[`pygrep_hooks`] Move `blanket-noqa` to noqa checker (`PGH004`) (#11053)
## Summary

Move `blanket-noqa` rule from the token checker to the noqa checker.
This allows us to make use of the line directives already computed in
the noqa checker.

## Test Plan

Verified test results are unchanged.
2024-04-22 13:36:25 -04:00
plredmond a9919707d4
[UP031] When encountering `"%s" % var` offer unsafe fix (#11019)
Resolves #10187

<details>
<summary>Old PR description; accurate through commit e86dd7d; probably
best to leave this fold closed</summary>

## Description of change

In the case of a printf-style format string with only one %-placeholder
and a variable at right (e.g. `"%s" % var`):

* The new behavior attempts to dereference the variable and then match
on the bound expression to distinguish between a 1-tuple (fix), n-tuple
(bug 🐛), or a non-tuple (fix). Dereferencing is via
`analyze::typing::find_binding_value`.
* If the variable cannot be dereferenced, then the type-analysis routine
is called to distinguish only tuple (no-fix) or non-tuple (fix). Type
analysis is via `analyze::typing::is_tuple`.
* If any of the above fails, the rule still fires, but no fix is
offered.

## Alternatives

* If the reviewers think that singling out the 1-tuple case is too
complicated, I will remove that.
* The ecosystem results show that no new fixes are detected. So I could
probably delete all the variable dereferencing code and code that tries
to generate fixes, tbh.

## Changes to existing behavior

**All the previous rule-firings and fixes are unchanged except for** the
"false negatives" in
`crates/ruff_linter/resources/test/fixtures/pyupgrade/UP031_1.py`. Those
previous "false negatives" are now true positives and so I moved them to
`crates/ruff_linter/resources/test/fixtures/pyupgrade/UP031_0.py`.

<details>
<summary>Existing false negatives that are now true positives</summary>

```
crates/ruff_linter/resources/test/fixtures/pyupgrade/UP031_0.py:134:1: UP031 Use format specifiers instead of percent format
    |
133 | # UP031 (no longer false negatives)
134 | 'Hello %s' % bar
    | ^^^^^^^^^^^^^^^^ UP031
135 |
136 | 'Hello %s' % bar.baz
    |
    = help: Replace with format specifiers

crates/ruff_linter/resources/test/fixtures/pyupgrade/UP031_0.py:136:1: UP031 Use format specifiers instead of percent format
    |
134 | 'Hello %s' % bar
135 |
136 | 'Hello %s' % bar.baz
    | ^^^^^^^^^^^^^^^^^^^^ UP031
137 |
138 | 'Hello %s' % bar['bop']
    |
    = help: Replace with format specifiers

crates/ruff_linter/resources/test/fixtures/pyupgrade/UP031_0.py:138:1: UP031 Use format specifiers instead of percent format
    |
136 | 'Hello %s' % bar.baz
137 |
138 | 'Hello %s' % bar['bop']
    | ^^^^^^^^^^^^^^^^^^^^^^^ UP031
    |
    = help: Replace with format specifiers
```
One of them newly offers a fix.
```
 # UP031 (no longer false negatives)
-'Hello %s' % bar
+'Hello {}'.format(bar)
```
This fix occurs because the new code dereferences `bar` to where it was
defined earlier in the file as a non-tuple:
```python
bar = {"bar": y}
```

---

</details>

## Behavior requiring new tests

Additionally, we now handle a few cases that we didn't previously test.
These cases are when a string has a single %-placeholder and the
righthand operand to the modulo operator is a variable **which can be
dereferenced.** One of those was shown in the previous section (the
"dereference non-tuple" case).

<details>
<summary>New cases handled</summary>

```
crates/ruff_linter/resources/test/fixtures/pyupgrade/UP031_0.py:126:1: UP031 [*] Use format specifiers instead of percent format
    |
125 | t1 = (x,)
126 | "%s" % t1
    | ^^^^^^^^^ UP031
127 | # UP031: deref t1 to 1-tuple, offer fix
    |
    = help: Replace with format specifiers

crates/ruff_linter/resources/test/fixtures/pyupgrade/UP031_0.py:130:1: UP031 Use format specifiers instead of percent format
    |
129 | t2 = (x,y)
130 | "%s" % t2
    | ^^^^^^^^^ UP031
131 | # UP031: deref t2 to n-tuple, this is a bug
    |
    = help: Replace with format specifiers
```
One of these offers a fix.
```
 t1 = (x,)
-"%s" % t1
+"{}".format(t1[0])
 # UP031: deref t1 to 1-tuple, offer fix
```
The other doesn't offer a fix because it's a bug.

---

</details>

---

</details>


## Changes to existing behavior

In the case of a string with a single %-placeholder and a single
ambiguous righthand argument to the modulo operator, (e.g. `"%s" % var`)
the rule now fires and offers a fix. We explain about this in the "fix
safety" section of the updated documentation.


## Documentation changes

I swapped the order of the "known problems" and the "examples" sections
so that the examples which describe the rule are first, before the
exceptions to the rule are described. I also tweaked the language to be
more explicit, as I had trouble understanding the documentation at
first. The "known problems" section is now "fix safety" but the content
is largely similar.

The diff of the documentation changes looks a little difficult unless
you look at the individual commits.
2024-04-22 08:40:51 -07:00
Jonathan Plasse a68938897d
[ruff] fix async comprehension false positive (RUF029) (#11070)
## Summary

- Fix #11043 

## Test Plan

Added the false positive code in the test fixture.
2024-04-21 08:17:25 -04:00
Charlie Marsh d544199272
Respect per-file-ignores for RUF100 with no other diagnostics (#11058)
## Summary

The existing test didn't cover the case in which there are _no_ other
diagnostics in the file.

Closes https://github.com/astral-sh/ruff/issues/10906.
2024-04-20 15:33:22 +00:00
Carl Meyer c80b9a4a90
Reduce size of Stmt from 144 to 120 bytes (#11051)
## Summary

I happened to notice that we box `TypeParams` on `StmtClassDef` but not
on `StmtFunctionDef` and wondered why, since `StmtFunctionDef` is bigger
and sets the size of `Stmt`.

@charliermarsh found that at the time we started boxing type params on
classes, classes were the largest statement type (see #6275), but that's
no longer true.

So boxing type-params also on functions reduces the overall size of
`Stmt`.

## Test Plan

The `<=` size tests are a bit irritating (since their failure doesn't
tell you the actual size), but I manually confirmed that the size is
actually 120 now.
2024-04-19 17:02:17 -06:00
Charlie Marsh 99f7f94538
Improve documentation around custom isort sections (#11050)
## Summary

Closes https://github.com/astral-sh/ruff/issues/11047.
2024-04-19 22:26:55 +00:00
James Frost 7b3c92a979
[flake8-bugbear] Document explicitly disabling strict zip (`B905`) (#11040)
Occasionally you intentionally have iterables of differing lengths. The
rule permits this by explicitly adding `strict=False`, but this was not
documented.

## Summary

The rule does not currently document how to avoid it when having
differing length iterables is intentional. This PR adds that to the rule
documentation.
2024-04-19 13:50:18 +00:00
Dhruv Manilawala 0ff25a540c
Bump version to 0.4.1 (#11035)
Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
2024-04-19 17:42:02 +05:30
Dhruv Manilawala d3cd61f804
Use empty range when there's "gap" in token source (#11032)
## Summary

This fixes a bug where the parser would panic when there is a "gap" in
the token source.

What's a gap?

The reason it's `<=` instead of just `==` is because there could be
whitespaces between
the two tokens. For example:

```python
#     last token end
#     | current token (newline) start
#     v v
def foo \n
#      ^
#      assume there's trailing whitespace here
```

Or, there could tokens that are considered "trivia" and thus aren't
emitted by the token
source. These are comments and non-logical newlines. For example:

```python
#     last token end
#     v
def foo # comment\n
#                ^ current token (newline) start
```

In either of the above cases, there's a "gap" between the end of the
last token and start
of the current token.

## Test Plan

Add test cases and update the snapshots.
2024-04-19 11:36:26 +00:00
Dhruv Manilawala 9bb23b0a38
Expect indented case block instead of match stmt (#11033)
## Summary

This PR adds a new `Clause::Case` and uses it to parse the body of a
`case` block. Earlier, it was using `Match` which would give an
incorrect error message like:

```
  |
1 | match subject:
2 |     case 1:
3 |     case 2: ...
  |     ^^^^ Syntax Error: Expected an indented block after `match` statement
  |
```

## Test Plan

Add test case and update the snapshot.
2024-04-19 16:46:15 +05:30
Charlie Marsh 06c248a126
[`ruff]` Ignore stub functions in `unused-async` (`RUF029`) (#11026)
## Summary

We should ignore methods that appear to be stubs, e.g.:

```python
async def foo() -> int: ...
```

Closes https://github.com/astral-sh/ruff/issues/11018.
2024-04-19 00:03:52 -04:00
Tibor Reiss 27902b7130
[`pylint`] Implement `invalid-index-returned` (`PLE0305`) (#10962)
Add pylint rule invalid-index-returned (PLE0305)

See https://github.com/astral-sh/ruff/issues/970 for rules

Test Plan: `cargo test`
2024-04-19 03:44:05 +00:00
Tibor Reiss adf63d9013
[`pylint`] Implement `invalid-hash-returned` (`PLE0309`) (#10961)
Add pylint rule invalid-hash-returned (PLE0309)

See https://github.com/astral-sh/ruff/issues/970 for rules

Test Plan: `cargo test`

TBD: from the description: "Strictly speaking `bool` is a subclass of
`int`, thus returning `True`/`False` is valid. To be consistent with
other rules (e.g.
[PLE0305](https://github.com/astral-sh/ruff/pull/10962)
invalid-index-returned), ruff will raise, compared to pylint which will
not raise."
2024-04-19 03:33:52 +00:00
MithicSpirit 5d3c9f2637
`ruff server`: fix Neovim setup guide command (#11021) 2024-04-19 08:24:09 +05:30
Charlie Marsh 33529c049e
Allow `NoReturn`-like functions for `__str__`, `__len__`, etc. (#11017)
## Summary

If the method always raises, we shouldn't raise a diagnostic for
"returning a value of the wrong type".

Closes https://github.com/astral-sh/ruff/issues/11016.
2024-04-18 22:55:15 +00:00
Zanie Blue e751b4ea82
Bump version to 0.4.0 (#11011)
Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
Co-authored-by: Dhruv Manilawala <dhruvmanila@gmail.com>
2024-04-18 19:10:28 +00:00
Dhruv Manilawala b7066e64e7
Consider binary expr for parenthesized with items parsing (#11012)
## Summary

This PR fixes the bug in with items parsing where it would fail to
recognize that the parenthesized expression is part of a large binary
expression.

## Test Plan

Add test cases and verified the snapshots.
2024-04-18 21:39:30 +05:30
Dhruv Manilawala 6c4d779140
Consider `if` expression for parenthesized with items parsing (#11010)
## Summary

This PR fixes the bug in parenthesized with items parsing where the `if`
expression would result into a syntax error.

The reason being that once we identify that the ambiguous left
parenthesis belongs to the context expression, the parser converts the
parsed with item into an equivalent expression. Then, the parser
continuous to parse any postfix expressions. Now, attribute, subscript,
and call are taken into account as they're grouped in
`parse_postfix_expression` but `if` expression has it's own parsing
function.

Use `parse_if_expression` once all postfix expressions have been parsed.
Ideally, I think that `if` could be included in postfix expression
parsing as they can be chained as well (`x if True else y if True else
z`).

## Test Plan

Add test cases and verified the snapshots.
2024-04-18 14:30:15 +00:00
Dhruv Manilawala 8020d486f6
Reset `FOR_TARGET` context for all kinds of parentheses (#11009)
## Summary

This PR fixes a bug in the new parser which involves the parser context
w.r.t. for statement. This is specifically around the `in` keyword which
can be present in the target expression and shouldn't be considered to
be part of the `for` statement header. Ideally it should use a context
which is passed between functions, thus using a call stack to set /
unset a specific variant which will be done in a follow-up PR as it
requires some amount of refactor.

## Test Plan

Add test cases and update the snapshots.
2024-04-18 19:37:50 +05:30
Dhruv Manilawala 13ffb5bc19
Replace LALRPOP parser with hand-written parser (#10036)
(Supersedes #9152, authored by @LaBatata101)

## Summary

This PR replaces the current parser generated from LALRPOP to a
hand-written recursive descent parser.

It also updates the grammar for [PEP
646](https://peps.python.org/pep-0646/) so that the parser outputs the
correct AST. For example, in `data[*x]`, the index expression is now a
tuple with a single starred expression instead of just a starred
expression.

Beyond the performance improvements, the parser is also error resilient
and can provide better error messages. The behavior as seen by any
downstream tools isn't changed. That is, the linter and formatter can
still assume that the parser will _stop_ at the first syntax error. This
will be updated in the following months.

For more details about the change here, refer to the PR corresponding to
the individual commits and the release blog post.

## Test Plan

Write _lots_ and _lots_ of tests for both valid and invalid syntax and
verify the output.

## Acknowledgements

- @MichaReiser for reviewing 100+ parser PRs and continuously providing
guidance throughout the project
- @LaBatata101 for initiating the transition to a hand-written parser in
#9152
- @addisoncrump for implementing the fuzzer which helped
[catch](https://github.com/astral-sh/ruff/pull/10903)
[a](https://github.com/astral-sh/ruff/pull/10910)
[lot](https://github.com/astral-sh/ruff/pull/10966)
[of](https://github.com/astral-sh/ruff/pull/10896)
[bugs](https://github.com/astral-sh/ruff/pull/10877)

---------

Co-authored-by: Victor Hugo Gomes <labatata101@linuxmail.org>
Co-authored-by: Micha Reiser <micha@reiser.io>
2024-04-18 17:57:39 +05:30
Alex Waygood e09180b1df
Rename `SemanticModel::is_builtin` to `SemanticModel::has_builtin_binding` (#10991) 2024-04-18 11:11:42 +01:00
Jane Lewis 2cc487eb22
`ruff server`: Introduce settings for directly configuring the linter and formatter (#10984)
## Summary

The following client settings have been introduced to the language
server:
* `lint.preview`
* `format.preview`
* `lint.select`
* `lint.extendSelect`
* `lint.ignore`
* `exclude`
* `lineLength`

`exclude` and `lineLength` apply to both the linter and formatter.

This does not actually use the settings yet, but makes them available
for future use.

## Test Plan

Snapshot tests have been updated.
2024-04-18 07:53:48 +00:00
Jane Lewis 5da7299b32
`ruff server`: Write a setup guide for Neovim (#10987)
## Summary

A setup guide has been written for NeoVim under a new
`crates/ruff_server/docs/setup` folder, where future setup guides will
also go. This setup guide was adapted from the [`ruff-lsp`
guide](https://github.com/astral-sh/ruff-lsp?tab=readme-ov-file#example-neovim).

---------

Co-authored-by: Dhruv Manilawala <dhruvmanila@gmail.com>
2024-04-18 02:46:30 +00:00
Charlie Marsh 4d8890eef5
[`pylint`] Omit stubs from `invalid-bool` and `invalid-str-return-type` (#11008)
## Summary

Reflecting some improvements that were made in
https://github.com/astral-sh/ruff/pull/10959.
2024-04-18 01:57:20 +00:00
Tibor Reiss 9f01ac3f87
[`pylint`] Implement `invalid-length-returned` (`E0303`) (#10963)
Add pylint rule invalid-length-returned (PLE0303)

See https://github.com/astral-sh/ruff/issues/970 for rules

Test Plan: `cargo test`

TBD: from the description: "Strictly speaking `bool` is a subclass of
`int`, thus returning `True`/`False` is valid. To be consistent with
other rules (e.g.
[PLE0305](https://github.com/astral-sh/ruff/pull/10962)
invalid-index-returned), ruff will raise, compared to pylint which will
not raise."
2024-04-18 01:54:52 +00:00
Charlie Marsh b23414e3cc
Resolve classes and functions relative to script name (#10965)
## Summary

If the user is analyzing a script (i.e., we have no module path), it
seems reasonable to use the script name when trying to identify paths to
objects defined _within_ the script.

Closes https://github.com/astral-sh/ruff/issues/10960.

## Test Plan

Ran:

```shell
check --isolated --select=B008 \
    --config 'lint.flake8-bugbear.extend-immutable-calls=["test.A"]' \
    test.py
```

On:

```python
class A: pass

def f(a=A()):
    pass
```
2024-04-18 01:42:50 +00:00
Tibor Reiss 1480d72643
[`pylint`] Implement `invalid-bytes-returned` (`E0308`) (#10959)
Add pylint rule invalid-bytes-returned (PLE0308)

See https://github.com/astral-sh/ruff/issues/970 for rules

Test Plan: `cargo test`
2024-04-18 01:38:14 +00:00
Charlie Marsh 06b3e376ac
Improve documentation for block comment rules (#11007)
Closes https://github.com/astral-sh/ruff/issues/10632.
2024-04-18 01:22:19 +00:00
Charlie Marsh e8b1125b30
[`flake8-slots`] Respect same-file `Enum` subclasses (#11006)
Closes https://github.com/astral-sh/ruff/issues/9890.
2024-04-17 21:15:52 -04:00
Zanie Blue 16cc9bd78d
Improve display of rules in `--show-settings` (#11003)
Closes https://github.com/astral-sh/ruff/issues/11002
2024-04-17 20:18:41 +00:00
Jane Lewis 0a6327418d
`ruff server` refreshes diagnostics for open files when file configuration is changed (#10988)
## Summary

The server now requests a [workspace diagnostic
refresh](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#diagnostic_refresh)
when a configuration file gets changed. This means that diagnostics for
all open files will be automatically re-requested by the client on a
config change.

## Test Plan

You can test this by opening several files in VS Code, setting `select`
in your file configuration to `[]`, and observing that the diagnostics
go away once the file is saved (besides any `Pylance` diagnostics).
Restore it to what it was before, and you should see the diagnostics
automatically return once a save happens.
2024-04-17 09:14:45 -07:00
Sigurd Spieckermann 518b29a9ef
Add `RUFF_OUTPUT_FILE` environment variable support (#10992)
## Summary

I've added support for configuring the `ruff check` output file via the
environment variable `RUFF_OUTPUT_FILE` akin to #1731.

This is super useful when, e.g., generating a [GitLab code quality
report](https://docs.gitlab.com/ee/ci/testing/code_quality.html#implement-a-custom-tool)
while running Ruff as a pre-commit hook. Usually, `ruff check` should
print its human-readable output to `stdout`, but when run through
`pre-commit` _in a GitLab CI job_ it should write its output in `gitlab`
format to a file. So, to override these two settings only during CI,
environment variables come handy, and `RUFF_OUTPUT_FORMAT` already
exists but `RUFF_OUTPUT_FILE` has been missing.

A (simplified) GitLab CI job config for this scenario might look like
this:

```yaml
pre-commit:
  stage: test
  image: python
  variables:
    RUFF_OUTPUT_FILE: gl-code-quality-report.json
    RUFF_OUTPUT_FORMAT: gitlab
  before_script:
    - pip install pre-commit
  script:
    - pre-commit run --all-files --show-diff-on-failure
  artifacts:
    reports:
      codequality: gl-code-quality-report.json
```

## Test Plan

I tested it manually.
2024-04-17 11:42:45 -04:00
Alex Waygood caae8d2c68
Optimise `SemanticModel::match_builtin_expr` (#11001) 2024-04-17 15:54:41 +01:00
Philipp Thiel 2971655b28
[`flake8-bugbear`] Treat `raise NotImplemented`-only bodies as stub functions (#10990)
## Summary

As discussed in
https://github.com/astral-sh/ruff/issues/10083#issuecomment-1969653610,
stubs detection now also covers the case where the function body raises
NotImplementedError and does nothing else.

## Test Plan

Tests for the relevant cases were added in B006_8.py
2024-04-17 14:06:40 +00:00
Alex Waygood f48a794125
Change more usages of `SemanticModel::is_builtin` to use `resolve_builtin_symbol` or `match_builtin_expr` (#10982)
## Summary

This PR switches more callsites of `SemanticModel::is_builtin` to move
over to the new methods I introduced in #10919, which are more concise
and more accurate. I missed these calls in the first PR.
2024-04-17 07:50:10 +01:00
Jane Lewis 2882604451
`ruff server`: Important errors are now shown as popups (#10951)
## Summary

Fixes #10866.

Introduces the `show_err_msg!` macro which will send a message to be
shown as a popup to the client via the `window/showMessage` LSP method.

## Test Plan

Insert various `show_err_msg!` calls in common code paths (for example,
at the beginning of `event_loop`) and confirm that these messages appear
in your editor.

To test that panicking works correctly, add this to the top of the `fn
run` definition in
`crates/ruff_server/src/server/api/requests/execute_command.rs`:

```rust
panic!("This should appear");
```

Then, try running a command like `Ruff: Format document` from the
command palette (`Ctrl/Cmd+Shift+P`). You should see the following
messages appear:


![Screenshot 2024-04-16 at 11 20
57 AM](https://github.com/astral-sh/ruff/assets/19577865/ae430da6-82c3-4841-a419-664ff34034e8)
2024-04-16 18:32:53 +00:00
Jane Lewis eab3c4e334
Enable ruff-specific source actions (#10916)
## Summary

Fixes #10780.

The server now send code actions to the client with a Ruff-specific
kind, `source.*.ruff`. The kind filtering logic has also been reworked
to support this.

## Test Plan

Add this to your `settings.json` in VS Code:

```json
{
  "[python]": {
    "editor.codeActionsOnSave": {
      "source.organizeImports.ruff": "explicit",
    },
  }
}
```

Imports should be automatically organized when you manually save with
`Ctrl/Cmd+S`.
2024-04-16 18:21:08 +00:00
Jane Lewis cffc55576f
`ruff server`: Resolve configuration for each document individually (#10950)
## Summary

Configuration is no longer the property of a workspace but rather of
individual documents. Just like the Ruff CLI, each document is
configured based on the 'nearest' project configuration. See [the Ruff
documentation](https://docs.astral.sh/ruff/configuration/#config-file-discovery)
for more details.

To reduce the amount of times we resolve configuration for a file, we
have an index for each workspace that stores a reference-counted pointer
to a configuration for a given folder. If another file in the same
folder is opened, the configuration is simply re-used rather than us
re-resolving it.

## Guide for reviewing

The first commit is just the restructuring work, which adds some noise
to the diff. If you want to quickly understand what's actually changed,
I recommend looking at the two commits that come after it.
f7c073d441 makes configuration a property
of `DocumentController`/`DocumentRef`, moving it out of `Workspace`, and
it also sets up the `ConfigurationIndex`, though it doesn't implement
its key function, `get_or_insert`. In the commit after it,
fc35618f17, we implement `get_or_insert`.

## Test Plan

The best way to test this would be to ensure that the behavior matches
the Ruff CLI. Open a project with multiple configuration files (or add
them yourself), and then introduce problems in certain files that won't
show due to their configuration. Add those same problems to a section of
the project where those rules are run. Confirm that the lint rules are
run as expected with `ruff check`. Then, open your editor and confirm
that the diagnostics shown match the CLI output.

As an example - I have a workspace with two separate folders, `pandas`
and `scipy`. I created a `pyproject.toml` file in `pandas/pandas/io` and
a `ruff.toml` file in `pandas/pandas/api`. I changed the `select` and
`preview` settings in the sub-folder configuration files and confirmed
that these were reflected in the diagnostics. I also confirmed that this
did not change the diagnostics for the `scipy` folder whatsoever.
2024-04-16 18:15:02 +00:00
Alex Waygood 4284e079b5
Improve inference capabilities of the `BuiltinTypeChecker` (#10976) 2024-04-16 18:53:22 +01:00
plredmond 65edbfe62f
Detect unneeded `async` keywords on functions (#9966)
## Summary

This change adds a rule to detect functions declared `async` but lacking
any of `await`, `async with`, or `async for`. This resolves #9951.

## Test Plan

This change was tested by following
https://docs.astral.sh/ruff/contributing/#rule-testing-fixtures-and-snapshots
and adding positive and negative cases for each of `await` vs nothing,
`async with` vs `with`, and `async for` vs `for`.
2024-04-16 10:32:29 -07:00
Max Muoto 45db695c47
Fix Typo for `extend-aliases` Option (#10978) 2024-04-16 12:23:09 -04:00
Micha Reiser 1801798e85
Bump the size of `RuleSet` (#10972) 2024-04-16 14:20:46 +02:00
Micha Reiser d4e140d47f
perf: `RuleTable::any_enabled` (#10971) 2024-04-16 12:20:27 +00:00
Alex Waygood f779babc5f
Improve handling of builtin symbols in linter rules (#10919)
Add a new method to the semantic model to simplify and improve the correctness of a common pattern
2024-04-16 11:37:31 +01:00
Charlie Marsh effd5188c9
[`flake8-bandit`] Allow `urllib.request.urlopen` calls with static `Request` argument (#10964)
## Summary

Allows, e.g.:

```python
import urllib

urllib.request.urlopen(urllib.request.Request("https://example.com/"))
```

...in
[`suspicious-url-open-usage`](https://docs.astral.sh/ruff/rules/suspicious-url-open-usage/).

See:
https://github.com/astral-sh/ruff/issues/7918#issuecomment-2057661054
2024-04-16 02:30:23 +00:00
StevenMia f9214f95bb
chore: remove repetitive words (#10952) 2024-04-15 12:57:48 +00:00
Steve C c2210359e7
[`pylint`] Implement `self-cls-assignment` (`W0642`) (#9267)
## Summary

This PR implements [`W0642`/`self-cls-assignment`](https://pylint.readthedocs.io/en/stable/user_guide/messages/warning/self-cls-assignment.html)

See: #970 

## Test Plan

Add test cases and verified the updated snapshots.

---------

Co-authored-by: Dhruv Manilawala <dhruvmanila@gmail.com>
2024-04-15 09:06:01 +00:00
Hoël Bagard 670d66f54c
[`pycodestyle`] Do not trigger `E3` rules on defs following a function/method with a dummy body (#10704) 2024-04-15 10:23:49 +02:00
Dhruv Manilawala f9a828f493
Move `Q003` to AST checker (#10923)
## Summary

This PR moves the `Q003` rule to AST checker.

This is the final rule that used the docstring detection state machine
and thus this PR removes it as well.

resolves: #7595 
resolves: #7808 

## Test Plan

- [x] `cargo test`
- [x] Make sure there are no changes in the ecosystem
2024-04-14 23:44:12 +05:30
Steve C 812b0976a9
[`pylint`] Support inverted comparisons (`PLR1730`) (#10920)
## Summary

Adds more aggressive logic to PLR1730, `if-stmt-min-max`

Closes #10907 

## Test Plan

`cargo test`

---------

Co-authored-by: Charlie Marsh <charlie.r.marsh@gmail.com>
2024-04-13 22:57:20 +00:00
Hoël Bagard b356c4376c
Fix S310 `suspicious-url-open-usage` description (#10917)
## Summary

The "What it does" section of the docstring is missing a verb, this PR
adds it.
2024-04-13 12:52:04 +01:00
Sebastian Pipping 85ca5b7eed
Fix last example of flake8-bugbear rule `B023` "function uses loop variable" (#10913)
<!--
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

Hi! 👋 

Thanks for sharing ruff as software libre — it helps me keep Python code
quality up with pre-commit, both locally and CI 🙏

While studying the examples at
https://docs.astral.sh/ruff/rules/function-uses-loop-variable/#example I
noticed that the last of the examples had a bug: prior to this fix, `ì`
was passed to the lambda for `x` rather than for `i` — the two are
mixed-up. The reason it's easy to overlook is because addition is an
commutative operation and so `x + i` and `i + x` give the same result
(and least with integers), despite the mix-up. For proof, let me demo
the relevant part with before and after:

```python
In [1]: from functools import partial

In [2]: [partial(lambda x, i: (x, i), i)(123) for i in range(3)]
Out[2]: [(0, 123), (1, 123), (2, 123)]

In [3]: [partial(lambda x, i: (x, i), i=i)(123) for i in range(3)]
Out[3]: [(123, 0), (123, 1), (123, 2)]
```

Does that make sense?

## Test Plan

<!-- How was it tested? -->
Was manually tested using IPython.


CC @r4f @grandchild
2024-04-12 20:07:52 +00:00
Charlie Marsh c2421068bc
Limit commutative non-augmented-assignments to primitive data types (#10912)
## Summary

I think this is the best we can do without type inference. At least it
will still catch some common cases.

Closes #10911.
2024-04-12 15:02:29 -04:00
Charlie Marsh e9870fe468
Avoid `non-augmented-assignment` for reversed, non-commutative operators (#10909)
Closes https://github.com/astral-sh/ruff/issues/10900.
2024-04-12 10:04:57 -04:00
Charlie Marsh a013050c11
Respect `per-file-ignores` for `RUF100` on blanket `# noqa` (#10908)
## Summary

If `RUF100` was included in a per-file-ignore, we respected it on cases
like `# noqa: F401`, but not the blanket variant (`# noqa`).

Closes https://github.com/astral-sh/ruff/issues/10906.
2024-04-12 13:45:29 +00:00
Dhruv Manilawala 2e37cf6b3b
Bump version to v0.3.7 (#10895) 2024-04-12 03:39:45 +00:00
wolfgangshi a9e4393008
[`pylint`] Implement rule to prefer augmented assignment (`PLR6104`) (#9932)
## Summary

Implement new rule: Prefer augmented assignment (#8877). It checks for
the assignment statement with the form of `<expr> = <expr>
<binary-operator> …` with a unsafe fix to use augmented assignment
instead.

## Test Plan

1. Snapshot test is included in the PR.
2. Manually test with playground.
2024-04-11 23:08:42 -04:00
Charlie Marsh 312f43475f
[`pylint`] Recode `nan-comparison` rule to `W0177` (#10894)
## Summary

This was accidentally committed under `W0117`, but the actual Pylint
code is `W0177`:
https://pylint.readthedocs.io/en/latest/user_guide/checkers/features.html.

Closes https://github.com/astral-sh/ruff/issues/10791.
2024-04-11 22:49:20 -04:00
Carl Meyer 563daa8a86
Fix docs and add overlap test for negated per-file-ignores (#10863)
Refs #3172 

## Summary

Fix a typo in the docs example, and add a test for the case where a
negative pattern and a positive pattern overlap.

The behavior here is simple: patterns (positive or negative) are always
additive if they hit (i.e. match for a positive pattern, don't match for
a negated pattern). We never "un-ignore" previously-ignored rules based
on a pattern (positive or negative) failing to hit.

It's simple enough that I don't really see other cases we need to add
tests for (the tests we have cover all branches in the ignores_from_path
function that implements the core logic), but open to reviewer feedback.

I also didn't end up changing the docs to explain this more, because I
think they are accurate as written and don't wrongly imply any more
complex behavior. Open to reviewer feedback on this as well!

After some discussion, I think allowing negative patterns to un-ignore
rules is too confusing and easy to get wrong; if we need that, we should
add `per-file-selects` instead.

## Test Plan

Test/docs only change; tests pass, docs render and look right.

---------

Co-authored-by: Alex Waygood <Alex.Waygood@gmail.com>
2024-04-11 19:30:28 -06:00
Carl Meyer 7ae15c6e0a
Fix comment copy/paste typo in newtype_index (#10892)
## Summary

This comment looks wrongly copy-pasted from the comment above, and
mentions the wrong type.

## Test Plan

Comment-only change.
2024-04-11 18:43:52 -06:00
Martin Imre 03899dcba3
[`flake8-bugbear`] Implement `loop-iterator-mutation` (`B909`) (#9578)
## Summary
This PR adds the implementation for the current
[flake8-bugbear](https://github.com/PyCQA/flake8-bugbear)'s B038 rule.
The B038 rule checks for mutation of loop iterators in the body of a for
loop and alerts when found.

Rational: 
Editing the loop iterator can lead to undesired behavior and is probably
a bug in most cases.

Closes #9511.

Note there will be a second iteration of B038 implemented in
`flake8-bugbear` soon, and this PR currently only implements the weakest
form of the rule.
I'd be happy to also implement the further improvements to B038 here in
ruff 🙂
See https://github.com/PyCQA/flake8-bugbear/issues/454 for more
information on the planned improvements.

## Test Plan
Re-using the same test file that I've used for `flake8-bugbear`, which
is included in this PR (look for the `B038.py` file).


Note: this is my first time using `rust` (beside `rustlings`) - I'd be
very happy about thorough feedback on what I could've done better
🙂 - Bring it on 😀
2024-04-11 19:52:52 +00:00
Carl Meyer 25f5a8b201
Struct not tuple for compiled per-file ignores (#10864)
## Summary

Code cleanup for per-file ignores; use a struct instead of a tuple.

Named the structs for individual ignores and the list of ignores
`CompiledPerFileIgnore` and `CompiledPerFileIgnoreList`. Name choice is
because we already have a `PerFileIgnore` struct for a
pre-compiled-matchers form of the config. Name bikeshedding welcome.

## Test Plan

Refactor, should not change behavior; existing tests pass.

---------

Co-authored-by: Alex Waygood <alex.waygood@gmail.com>
2024-04-11 13:47:57 -06:00
Charlie Marsh e7d1d43f39
[`pylint`] Reverse min-max logic in `if-stmt-min-max` (#10890)
Closes https://github.com/astral-sh/ruff/issues/10889.
2024-04-11 14:16:13 -04:00
Charlie Marsh 0cc154c2a9
Avoid TOCTOU errors in cache initialization (#10884)
## Summary

I believe this should close
https://github.com/astral-sh/ruff/issues/10880? The `.gitignore`
creation seems ok, since it truncates, but using `cachedir::is_tagged`
followed by `cachedir::add_tag` is not safe, as `cachedir::add_tag`
_fails_ if the file already exists.

This also matches the structure of the code in `uv`.

Closes https://github.com/astral-sh/ruff/issues/10880.
2024-04-11 12:09:07 -04:00
Dhruv Manilawala 4e8a84617c
Bump version to v0.3.6 (#10883)
Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
2024-04-11 15:53:01 +00:00
Auguste Lalande ffea1bb0a3
[`refurb`] Implement `write-whole-file` (`FURB103`) (#10802)
## Summary

Implement `write-whole-file` (`FURB103`), part of #1348. This is largely
a copy and paste of `read-whole-file` #7682.

## Test Plan

Text fixture added.

---------

Co-authored-by: Dhruv Manilawala <dhruvmanila@gmail.com>
2024-04-11 14:21:45 +05:30
Charlie Marsh 1eee6f16e4
[`flake8-pytest-style`] Fix single-tuple conversion in `pytest-parametrize-values-wrong-type` (#10862)
## Summary

This looks like a typo (without test coverage).

Closes https://github.com/astral-sh/ruff/issues/10861.
2024-04-10 14:20:09 -04:00
Auguste Lalande de46a36bbc
[`pygrep-hooks`] Improve `blanket-noqa` error message (`PGH004`) (#10851)
## Summary

Improve `blanket-noqa` error message in cases where codes are provided
but not detected due to formatting issues. Namely `# noqa X100` (missing
colon) or `noqa : X100` (space before colon). The behavior is similar to
`NQA002` and `NQA003` from `flake8-noqa` mentioned in #850. The idea to
merge the rules into `PGH004` was suggested by @MichaReiser
https://github.com/astral-sh/ruff/pull/10325#issuecomment-2025535444.

## Test Plan

Test cases added to fixture.
2024-04-10 04:30:25 +00:00
Charlie Marsh dbf8d0c82c
Show negated condition in `needless-bool` diagnostics (#10854)
## Summary

Closes https://github.com/astral-sh/ruff/issues/10843.
2024-04-10 04:29:43 +00:00
Carl Meyer 02e88fdbb1
Support negated patterns in [extend-]per-file-ignores (#10852)
Fixes #3172 

## Summary

Allow prefixing [extend-]per-file-ignores patterns with `!` to negate
the pattern; listed rules / prefixes will be ignored in all files that
don't match the pattern.

## Test Plan

Added tests for the feature.

Rendered docs and checked rendered output.
2024-04-09 21:53:41 -06:00
Carl Meyer 42d52ebbec
Support FORCE_COLOR env var (#10839)
Fixes #5499 

## Summary

Add support for `FORCE_COLOR` env var, as specified at
https://force-color.org/

## Test Plan

I wrote an integration test for this, and then realized that can't work,
since we use a dev-dependency on `colored` with the `no-color` feature
to avoid ANSI color codes in test snapshots.

So this is just tested manually.

`cargo run --features test-rules -- check --no-cache --isolated -
--select RUF901 --diff < /dev/null` shows a colored diff.
`cargo run --features test-rules -- check --no-cache --isolated -
--select RUF901 --diff < /dev/null | less` does not have color, since we
pipe it to `less`.
`FORCE_COLOR=1 cargo run --features test-rules -- check --no-cache
--isolated - --select RUF901 --diff < /dev/null | less` does have color
(after this diff), even though we pipe it to `less`.
2024-04-08 15:29:29 -06:00
Carl Meyer e13e57e024
Localize cleanup for FunctionDef and ClassDef (#10837)
## Summary

Came across this code while digging into the semantic model with
@AlexWaygood, and found it confusing because of how it splits
`push_scope` from the paired `pop_scope` (took me a few minutes to even
figure out if/where we were popping the pushed scope). Since this
"cleanup" is already totally split by node type, there doesn't seem to
be any gain in having it as a separate "step" rather than just
incorporating it into the traversal clauses for those node types.

I left the equivalent cleanup step alone for the expression case,
because in that case it is actually generic across several different
node types, and due to the use of the common `visit_generators` utility
there isn't a clear way to keep the pushes and corresponding pops
localized.

Feel free to just reject this if I've missed a good reason for it to
stay this way!

## Test Plan

Tests and clippy.
2024-04-08 13:29:38 -06:00
Jane Lewis c3e28f9d55
The linter and code actions can now be disabled in client settings for `ruff server` (#10800)
## Summary

This is a follow-up to https://github.com/astral-sh/ruff/pull/10764.
Support for diagnostics, quick fixes, and source actions can now be
disabled via client settings.

## Test Plan

### Manual Testing

Set up your workspace as described in the test plan in
https://github.com/astral-sh/ruff/pull/10764, up to step 2. You don't
need to add a debug statement.
The configuration for `folder_a` and `folder_b` should be as follows:
`folder_a`:
```json
{
    "ruff.codeAction.fixViolation": {
        "enable": true
    }
}
```

`folder_b`
```json
{
    "ruff.codeAction.fixViolation": {
        "enable": false
    }
}
```
Finally, open up your VS Code User Settings and un-check the `Ruff > Fix
All` setting.

1. Open a Python file in `folder_a` that has existing problems. The
problems should be highlighted, and quick fix should be available.
`source.fixAll` should not be available as a source action.
2. Open a Python file in `folder_b` that has existing problems. The
problems should be highlighted, but quick fixes should not be available
for any of them. `source.fixAll` should not be available as a source
action.
3. Open up your VS Code Workspace Settings (second tab under the search
bar) and un-check `Ruff > Lint: Enable`
4. Both files you tested in steps 1 and 2 should now lack any visible
diagnostics. `source.organizeImports` should still be available as a
source action.
2024-04-08 07:53:28 -07:00
Aleksei Latyshev 6050bab5db
[`refurb`] Support `itemgetter` in `reimplemented-operator` (`FURB118`) (#10526)
## Summary
Lint about function like expressions which are equivalent to
`operator.itemgetter`.
See:
https://github.com/astral-sh/ruff/issues/1348#issuecomment-1909421747

## Test Plan
cargo test
2024-04-07 02:31:59 +00:00
Alex Waygood 2a51dcfdf7
[`pyflakes`] Allow forward references in class bases in stub files (`F821`) (#10779)
## Summary

Fixes #3011.

Type checkers currently allow forward references in all contexts in stub
files, and stubs frequently make use of this capability (although it
doesn't actually seem to be specc'd anywhere --neither in PEP 484, nor
https://typing.readthedocs.io/en/latest/source/stubs.html#id6, nor the
CPython typing docs). Implementing it so that Ruff allows forward
references in _all contexts_ in stub files seems non-trivial, however
(or at least, I couldn't figure out how to do it easily), so this PR
does not do that. Perhaps it _should_; if we think this apporach isn't
principled enough, I'm happy to close it and postpone changing anything
here.

However, this does reduce the number of F821 errors Ruff emits on
typeshed down from 76 to 2, which would mean that we could enable the
rule at typeshed. The remaining 2 F821 errors can be trivially fixed at
typeshed by moving definitions around; forward references in class bases
were really the only remaining places where there was a real _use case_
for forward references in stub files that Ruff wasn't yet allowing.

## Test plan

`cargo test`. I also ran this PR branch on typeshed to check to see if
there were any new false positives caused by the changes here; there
were none.
2024-04-07 01:15:58 +01:00
Alex Waygood 86588695e3
[`flake8-slots`] Flag subclasses of call-based `typing.NamedTuple`s as well as subclasses of `collections.namedtuple()` (`SLOT002`) (#10808) 2024-04-07 00:16:06 +01:00
Alex Waygood 47e0cb8985
[`flake8-pyi`] Various improvements to PYI034 (#10807)
More accurately identify whether a class is a metaclass, a subclass of `collections.abc.Iterator`, or a subclass of `collections.abc.AsyncIterator`
2024-04-07 00:15:48 +01:00
renovate[bot] 388658efdb
Update pre-commit dependencies (#10698)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Zanie Blue <contact@zanie.dev>
Co-authored-by: Alex Waygood <alex.waygood@gmail.com>
2024-04-06 23:00:41 +00:00
Tibor Reiss 3194f90db1
[`pylint`] Implement `if-stmt-min-max` (`PLR1730`, `PLR1731`) (#10002)
Add rule [consider-using-min-builtin
(R1730)](https://pylint.readthedocs.io/en/latest/user_guide/messages/refactor/consider-using-min-builtin.html)
and [consider-using-max-builtin
(R1731)](https://pylint.readthedocs.io/en/latest/user_guide/messages/refactor/consider-using-max-builtin.html)

See https://github.com/astral-sh/ruff/issues/970 for rules

Test Plan: `cargo test`
2024-04-06 17:32:05 +00:00
Charlie Marsh ee4bff3475
Add comment test for `FURB110` (#10804) 2024-04-06 16:49:22 +00:00
Auguste Lalande 7fb012d0df
[`refurb`] Do not allow any keyword arguments for `read-whole-file` in `rb` mode (`FURB101`) (#10803)
## Summary

`Path.read_bytes()` does not support any keyword arguments, so `FURB101`
should not be triggered if the file is opened in `rb` mode with any
keyword arguments.

## Test Plan

Move erroneous test to "Non-error" section of fixture.
2024-04-06 12:41:39 -04:00
Steve C 44459f92ef
[`refurb`] Implement `if-expr-instead-of-or-operator` (`FURB110`) (#10687)
## Summary

Add
[`FURB110`](https://github.com/dosisod/refurb/blob/master/refurb/checks/logical/use_or.py)

See: #1348 

## Test Plan

`cargo test`
2024-04-06 16:39:40 +00:00
Alex Waygood 1dc93107dc
Improve internal documentation for the semantic model (#10788) 2024-04-06 16:28:32 +00:00
Charlie Marsh 7fb5f47efe
Respect `# noqa` directives on `__all__` openers (#10798)
## Summary

Historically, given:

```python
__all__ = [  # noqa: F822
    "Bernoulli",
    "Beta",
    "Binomial",
]
```

The F822 violations would be attached to the `__all__`, so this `# noqa`
would be enforced for _all_ definitions in the list. This changed in
https://github.com/astral-sh/ruff/pull/10525 for the better, in that we
now use the range of each string. But these `# noqa` directives stopped
working.

This PR sets the `__all__` as a parent range in the diagnostic, so that
these directives are respected once again.

Closes https://github.com/astral-sh/ruff/issues/10795.

## Test Plan

`cargo test`
2024-04-06 14:51:17 +00:00
Charlie Marsh 83db62bcda
Use within-scope shadowed bindings in `asyncio-dangling-task` (#10793)
## Summary

I think this is using the wrong shadowing, as seen by the change in the
test fixture.
2024-04-06 10:44:03 -04:00
Bohdan b45fd61ec5
[`pyupgrade`] Replace `str, Enum` with `StrEnum` (`UP042`) (#10713)
## Summary

Add new rule `pyupgrade - UP042` (I picked next available number).
Closes https://github.com/astral-sh/ruff/discussions/3867
Closes https://github.com/astral-sh/ruff/issues/9569

It should warn + provide a fix `class A(str, Enum)` -> `class
A(StrEnum)` for py311+.

## Test Plan

Added UP042.py test.

## Notes

I did not find a way to call `remove_argument` 2 times consecutively, so
the automatic fixing works only for classes that inherit exactly `str,
Enum` (regardless of the order).

I also plan to extend this rule to support IntEnum in next PR.
2024-04-06 01:56:28 +00:00
Jane Lewis 323264dec2
Remove debug print when resolving client settings in `ruff server` (#10799)
This was a statement used as part of the test plan in #10764 that was
erroneously committed in 8aa31f4c74.
2024-04-06 00:13:25 +00:00
Jane Lewis c11e6d709c
`ruff server` now supports commands for auto-fixing, organizing imports, and formatting (#10654)
## Summary

This builds off of the work in
https://github.com/astral-sh/ruff/pull/10652 to implement a command
executor, backwards compatible with the commands from the previous LSP
(`ruff.applyAutofix`, `ruff.applyFormat` and
`ruff.applyOrganizeImports`).

This involved a lot of refactoring and tweaks to the code action
resolution code - the most notable change is that workspace edits are
specified in a slightly different way, using the more general `changes`
field instead of the `document_changes` field (which isn't supported on
all LSP clients). Additionally, the API for synchronous request handlers
has been updated to include access to the `Requester`, which we use to
send a `workspace/applyEdit` request to the client.

## Test Plan



https://github.com/astral-sh/ruff/assets/19577865/7932e30f-d944-4e35-b828-1d81aa56c087
2024-04-05 23:27:35 +00:00
Jane Lewis a184dc68f5
Implement client setting initialization and resolution for `ruff server` (#10764)
## Summary

When a language server initializes, it is passed a serialized JSON
object, which is known as its "initialization options". Until now, `ruff
server` has ignored those initialization options, meaning that
user-provided settings haven't worked. This PR is the first step for
supporting settings from the LSP client. It implements procedures to
deserialize initialization options into a settings object, and then
resolve those settings objects into concrete settings for each
workspace.

One of the goals for user settings implementation in `ruff server` is
backwards compatibility with `ruff-lsp`'s settings. We won't support all
settings that `ruff-lsp` had, but the ones that we do support should
work the same and use the same schema as `ruff-lsp`.

These are the existing settings from `ruff-lsp` that we will continue to
support, and which are part of the settings schema in this PR:

| Setting | Default Value | Description |

|----------------------------------------|---------------|----------------------------------------------------------------------------------------|
| `codeAction.disableRuleComment.enable` | `true` | Whether to display
Quick Fix actions to disable rules via `noqa` suppression comments. |
| `codeAction.fixViolation.enable` | `true` | Whether to display Quick
Fix actions to autofix violations. |
| `fixAll` | `true` | Whether to register Ruff as capable of handling
`source.fixAll` actions. |
| `lint.enable` | `true` | Whether to enable linting. Set to `false` to
use Ruff exclusively as a formatter. |
| `organizeImports` | `true` | Whether to register Ruff as capable of
handling `source.organizeImports` actions. |

To be clear: this PR does not implement 'support' for these settings,
individually. Rather, it constructs a framework for these settings to be
used by the server in the future.

Notably, we are choosing *not* to support `lint.args` and `format.args`
as settings for `ruff server`. This is because we're now interfacing
with Ruff at a lower level than its CLI, and converting CLI arguments
back into configuration is too involved.

We will have support for linter and formatter specific settings in
follow-up PRs. We will also 'hook up' user settings to work with the
server in follow up PRs.

## Test Plan

### Snapshot Tests

Tests have been created in
`crates/ruff_server/src/session/settings/tests.rs` to ensure that
deserialization and settings resolution works as expected.

### Manual Testing

Since we aren't using the resolved settings anywhere yet, we'll have to
add a few printing statements.

We want to capture what the resolved settings look like when sent as
part of a snapshot, so modify `Session::take_snapshot` to be the
following:

```rust
    pub(crate) fn take_snapshot(&self, url: &Url) -> Option<DocumentSnapshot> {
        let resolved_settings = self.workspaces.client_settings(url, &self.global_settings);
        tracing::info!("Resolved settings for document {url}: {resolved_settings:?}");
        Some(DocumentSnapshot {
            configuration: self.workspaces.configuration(url)?.clone(),
            resolved_client_capabilities: self.resolved_client_capabilities.clone(),
            client_settings: resolved_settings,
            document_ref: self.workspaces.snapshot(url)?,
            position_encoding: self.position_encoding,
            url: url.clone(),
        })
    }
```

Once you've done that, build the server and start up your extension
testing environment.

1. Set up a workspace in VS Code with two workspace folders, each one
having some variant of Ruff file-based configuration (`pyproject.toml`,
`ruff.toml`, etc.). We'll call these folders `folder_a` and `folder_b`.
2. In each folder, open up `.vscode/settings.json`.
3. In folder A, use these settings:
```json
{
    "ruff.codeAction.disableRuleComment": {
        "enable": true
    }
}
```
4. In folder B, use these settings:
```json
{
    
    "ruff.codeAction.disableRuleComment": {
        "enable": false
    }
}
```
5. Finally, open up your VS Code User Settings and un-check the `Ruff >
Code Action: Disable Rule Comment` setting.
6. When opening files in `folder_a`, you should see logs that look like
this:
```
Resolved settings for document <file>: ResolvedClientSettings { fix_all: true, organize_imports: true, lint_enable: true, disable_rule_comment_enable: true, fix_violation_enable: true }
```
7. When opening files in `folder_b`, you should see logs that look like
this:
```
Resolved settings for document <file>: ResolvedClientSettings { fix_all: true, organize_imports: true, lint_enable: true, disable_rule_comment_enable: false, fix_violation_enable: true }
```
8. To test invalid configuration, change `.vscode/settings.json` in
either folder to be this:
```json
{
    "ruff.codeAction.disableRuleComment": {
        "enable": "invalid"
    },
}
```
10. You should now see these error logs:
```
<time> [info]    <duration> ERROR ruff_server::session::settings Failed to deserialize initialization options: data did not match any variant of untagged enum InitializationOptions. Falling back to default client settings...

<time> [info]    <duration> WARN ruff_server::server No workspace settings found for file:///Users/jane/testbed/pandas
   <duration> WARN ruff_server::server No workspace settings found for file:///Users/jane/foss/scipy
```
11. Opening files in either folder should now print the following
configuration:
```
Resolved settings for document <file>: ResolvedClientSettings { fix_all: true, organize_imports: true, lint_enable: true, disable_rule_comment_enable: true, fix_violation_enable: true }
```
2024-04-05 22:41:50 +00:00
Auguste Lalande c2790f912b
[`pylint`] Implement `bad-staticmethod-argument` (`PLW0211`) (#10781)
## Summary

Implement `bad-staticmethod-argument` from pylint, part of #970.

## Test Plan

Text fixture added.
2024-04-05 21:33:39 +00:00
Micha Reiser 2e7a1a4cb1
D403: Require capitalizing single word sentence (#10776) 2024-04-05 08:42:00 +02:00
Jane Lewis d050d6da2e
`ruff server` now supports the `source.organizeImports` source action (#10652)
## Summary

This builds on top of the work in
https://github.com/astral-sh/ruff/pull/10597 to support `Ruff: Organize
imports` as an available source action.

To do this, we have to support `Clone`-ing for linter settings, since we
need to modify them in place to select import-related diagnostics
specifically (`I001` and `I002`).

## Test Plan


https://github.com/astral-sh/ruff/assets/19577865/04282d01-dfda-4ac5-aa8f-6a92d5f85bfd
2024-04-04 22:20:50 +00:00
Dhruv Manilawala d02b1069b5
Add semantic model flag when inside f-string replacement field (#10766)
## Summary

This PR adds a new semantic model flag to indicate that the checker is
inside an f-string replacement field. This will be used to ignore
certain checks if the target version doesn't support a specific feature
like PEP 701.

fixes: #10761 

## Test Plan

Add a test case from the raised issue.
2024-04-04 09:08:48 +05:30
Alex Waygood 6b4fa17097
Rework docs for pydocstyle rules (#10754) 2024-04-03 22:34:00 +01:00
Carl Meyer 5e2482824c
[flake8_comprehensions] add sum/min/max to unnecessary comprehension check (C419) (#10759)
Fixes #3259 

## Summary

Renames `UnnecessaryComprehensionAnyAll` to
`UnnecessaryComprehensionInCall` and extends the check to `sum`, `min`,
and `max`, in addition to `any` and `all`.

## Test Plan

Updated snapshot test.

Built docs locally and verified the docs for this rule still render
correctly.
2024-04-03 14:44:33 -06:00
Carl Meyer e0a8fb607a
fix obsolete name in resolve_qualified_name docs (#10762)
`resolve_call_path` was renamed to `resolve_qualified_name` in
a6d892b1f4, but the doc block for the
function wasn't updated to match.
2024-04-03 20:13:10 +00:00
Jane Lewis 257964a8bc
`ruff server` now supports `source.fixAll` source action (#10597)
## Summary

`ruff server` now has source action `source.fixAll` as an available code
action.

This also fixes https://github.com/astral-sh/ruff/issues/10593 in the
process of revising the code for quick fix code actions.

## Test Plan




https://github.com/astral-sh/ruff/assets/19577865/f4c07425-e68a-445f-a4ed-949c9197a6be
2024-04-03 16:22:17 +00:00
Boshen d467aa78c2
Remove an unused dependency (#10747)
## Summary

Continuation of #10475, I improved [`cargo
shear`](https://github.com/Boshen/cargo-shear) even more.

We can put this in CI once I test it a bit more, given that [ignoring
false
positives](https://github.com/Boshen/cargo-shear?tab=readme-ov-file#ignore-false-positives)
has been implemented.

## Test Plan

`cargo check --all-features --all-targets`
2024-04-03 09:57:19 +01:00
Jane Lewis 9872f51293
Drop support for `root_uri` as an initialization parameter in `ruff_server` (#10743)
## Summary

Needed for https://github.com/astral-sh/ruff/pull/10686.

We no longer support `root_uri` as an initialization parameter, relying
solely on `workspace_folders` to find the working directories. This
means that the minimum supported LSP version is now `0.3.6`.

## Test Plan

When opening a folder in VS Code, you shouldn't see any errors in the
log which say `No workspace(s) were provided(...)`.
2024-04-02 20:51:59 -07:00
Charlie Marsh e54b591ec7
Use section name range for all section-related docstring diagnostics (#10740)
## Summary

We may not have had access to this in the past, but in short, if the
diagnostic is related to a specific section of a docstring, it seems
better to highlight the section (via the header) than the _entire_
docstring.

This should be completely compatible with existing `# noqa` since it's
always inside of a multi-line string anyway, and in such cases the `#
noqa` is always placed at the end of the multiline string.

Closes https://github.com/astral-sh/ruff/issues/10736.
2024-04-02 22:10:04 -04:00
Carl Meyer 814b26f82e
[flake8_comprehensions] update docs for unnecessary-comprehension-any-all (C419) (#10744)
Ref #3259; see in particular
https://github.com/astral-sh/ruff/issues/3259#issuecomment-2033127339

## Summary

Improve the accuracy of the docs for this lint rule/fix.

## Test Plan

Generated the docs locally and visited the page for this rule:

![Screenshot 2024-04-02 at 4 56
40 PM](https://github.com/astral-sh/ruff/assets/61586/64f25cf6-edfe-4682-ac8e-7e21b834f5f2)

---------

Co-authored-by: Zanie Blue <contact@zanie.dev>
2024-04-02 17:42:55 -06:00
Charlie Marsh dff8f93457
[`flake8-return`] Ignore assignments to annotated variables in `unnecessary-assign` (#10741)
## Summary

Closes https://github.com/astral-sh/ruff/issues/10732.
2024-04-02 16:18:05 -04:00
Aleksei Latyshev 859e3fc7fa
[`refurb`] Implement `int-on-sliced-str` (`FURB166`) (#10650)
## Summary
implement int_on_sliced_str (FURB166) lint
- #1348
- [original
lint](https://github.com/dosisod/refurb/blob/master/refurb/checks/builtin/use_int_base_zero.py)

## Test Plan
cargo test
2024-04-02 19:29:42 +00:00
Aleksei Latyshev 0de23760ff
[`pylint`] Don't recommend decorating staticmethods with `@singledispatch` (`PLE1519`, `PLE1520`) (#10637)
Co-authored-by: Alex Waygood <alex.waygood@gmail.com>
2024-04-02 16:47:31 +00:00
Dhruv Manilawala 99dd3a8ab0
Implement `as_str` & `Display` for all operator enums (#10691)
## Summary

This PR adds the `as_str` implementation for all the operator methods.
It already exists for `CmpOp` which is being [used in the
linter](ffcd77860c/crates/ruff_linter/src/rules/flake8_simplify/rules/key_in_dict.rs (L117))
and it makes sense to implement it for the rest as well. This will also
be utilized in error messages for the new parser.
2024-04-02 10:34:36 +00:00
Dhruv Manilawala eee2d5b915
Remove unused operator methods and impl (#10690)
## Summary

This PR removes unused operator methods and impl traits. There is
already the `is_macro::Is` implementation for all the operators and this
seems unnecessary.
2024-04-02 15:53:20 +05:30
Charlie Marsh 159bad73d5
Accept non-aliased (but correct) import in unconventional-import-alias (#10729)
## Summary

Given:

```toml
[tool.ruff.lint.flake8-import-conventions.aliases]
"django.conf.settings" = "settings"
```

We should accept `from django.conf import settings`.

Closes https://github.com/astral-sh/ruff/issues/10599.
2024-04-01 23:47:20 -04:00
Charlie Marsh 7b48443624
Respect `Q00*` ignores in `flake8-quotes` rules (#10728)
## Summary

We lost the per-rule ignores when these were migrated to the AST, so if
_any_ `Q` rule is enabled, they're now all enabled.

Closes https://github.com/astral-sh/ruff/issues/10724.

## Test Plan

Ran:

```shell
ruff check . --isolated --select Q --ignore Q000
ruff check . --isolated --select Q --ignore Q001
ruff check . --isolated --select Q --ignore Q002
ruff check . --isolated --select Q --ignore Q000,Q001
ruff check . --isolated --select Q --ignore Q000,Q002
ruff check . --isolated --select Q --ignore Q001,Q002
```

...against:

```python
'''
bad docsting
'''
a = 'single'
b = '''
bad multi line
'''
```
2024-04-02 03:21:12 +00:00
Charlie Marsh d36f60999d
Ignore annotated lambdas in class scopes (#10720)
## Summary

An annotated lambda assignment within a class scope is often
intentional. For example, within a dataclass or Pydantic model, these
are treated as fields rather than methods (and so can be passed values
in constructors).

I originally wrote this to special-case dataclasses and Pydantic
models... But was left feeling like we'd see more false positives here
for little gain (an annotated lambda within a `class` is likely
intentional?). Open to opinions, though.

Closes https://github.com/astral-sh/ruff/issues/10718.
2024-04-01 15:44:45 -04:00
Charlie Marsh 67f0f615b2
Recursively resolve `TypeDicts` for N815 violations (#10719)
## Summary

Only works within a single file for now.

Closes https://github.com/astral-sh/ruff/issues/10671.
2024-04-01 17:40:55 +00:00
Charlie Marsh 200ebeebdc
Bump version to v0.3.5 (#10717) 2024-04-01 13:15:32 -04:00
renovate[bot] a0e1544848
chore(deps): update rust crate pep440_rs to 0.5.0 (#10703) 2024-04-01 16:02:18 +00:00
renovate[bot] 4047d456b6
chore(deps): update rust crate insta to v1.38.0 (#10701) 2024-04-01 15:44:30 +00:00
Steve C f6b6f0df67
[`ruff`] Fix panic in unused `# noqa` removal with multi-byte space (`RUF100`) (#10682)
## Summary

Currently, [this
line](716688d44e/crates/ruff_linter/src/fix/edits.rs (L101))
assumes that the `noqa` comment begins with an octothorpe followed by a
space. (`# `) With anyone's random code, this of course is not always
true.

When there's a multi-byte character after the leading octothorpe, such
as
[`\u0085`](https://www.fileformat.info/info/unicode/char/85/index.htm),
we try slicing from within the character, causing a panic.

To fix this, the logic has been changed to remove unused `noqa`
directives and keep any trailing comments, or removing the whole comment
if the comment is just the unused `noqa`

Fixes #10097.

## Test Plan

`cargo test`
2024-04-01 01:00:37 +00:00
hikaru-kajita 716688d44e
[`pylint`] Implement `modified-iterating-set` (`E4703`) (#10473)
## Summary

Implement `E4703` in the issue #970.
Relevant pylint docs is here:
https://pylint.readthedocs.io/en/stable/user_guide/messages/error/modified-iterating-set.html

## Test Plan

I've written it in the `modified_iterating_set.py`.
2024-03-31 14:37:49 +00:00
hikaru-kajita 9ad9cea952
[`refurb`] Implement `unnecessary-from-float` (`FURB164`) (#10647)
## Summary

<!-- What's the purpose of the change? What does it do, and why? -->

Implement FURB164 in the issue #1348.
Relevant Refurb docs is here:
https://github.com/dosisod/refurb/blob/v2.0.0/docs/checks.md#furb164-no-from-float

I've changed the name from `no-from-float` to
`verbose-decimal-fraction-construction`.

## Test Plan

<!-- How was it tested? -->

I've written it in the `FURB164.py`.

---------

Co-authored-by: Charlie Marsh <charlie.r.marsh@gmail.com>
2024-03-30 07:04:01 -04:00
Charlie Marsh 75e01420fa
Always place non-relative imports after relative imports (#10669)
## Summary

When `relative-imports-order = "closest-to-furthest"` is set, we should
_still_ put non-relative imports after relative imports. It's rare for
them to be in the same section, but _possible_ if you use
`known-local-folder`.

Closes https://github.com/astral-sh/ruff/issues/10655.

## Test Plan

New tests.

Also sorted this file:

```python
from ..models import ABC
from .models import Question
from .utils import create_question
from django_polls.apps.polls.models import Choice
```

With both:

- `isort view.py`
- `ruff check view.py --select I --fix`

And the following `pyproject.toml`:

```toml
[tool.ruff.lint.isort]
order-by-type = false
relative-imports-order = "closest-to-furthest"
known-local-folder = ["django_polls"]

[tool.isort]
profile = "black"
reverse_relative = true
known_local_folder = ["django_polls"]
```

I verified that Ruff and isort gave the same result, and that they
_still_ gave the same result when removing the relevant setting:

```toml
[tool.ruff.lint.isort]
order-by-type = false
known-local-folder = ["django_polls"]

[tool.isort]
profile = "black"
known_local_folder = ["django_polls"]
```
2024-03-29 22:13:54 -04:00
Charlie Marsh fc54f53662
Make `unnecessary-lambda` an always-unsafe fix (#10668)
## Summary

See the linked issue and comment for more.

Closes https://github.com/astral-sh/ruff/issues/10663.
2024-03-30 01:05:05 +00:00
Charlie Marsh 7c2e9f71ea
Change `quadratic-list-summation` docs to use `iadd` consistently (#10666)
Closes https://github.com/astral-sh/ruff/issues/10088.
2024-03-30 00:32:34 +00:00
Auguste Lalande 3c48913473
[`flake8-boolean-trap`] Add setting for user defined allowed boolean trap (#10531)
## Summary

Add a setting `extend-allowed-calls` to allow users to define their own
list of calls which allow boolean traps.

Resolves #10485.
Resolves #10356.

## Test Plan

Extended text fixture and added setting test.
2024-03-30 00:26:12 +00:00
Dhruv Manilawala 1bcdfe268d
Allow f-strings with `%z` for `DTZ007` (#10651)
## Summary

This PR fixes the bug for `DTZ007` rule where it didn't consider to
check for the presence of `%z` in f-strings. It also considers the
string parts of an implicitly concatenated f-strings for which I want to
find a better solution (#10308).

fixes: #10601 

## Test Plan

Add test cases and update the snapshots.
2024-03-29 09:57:13 +05:30
Mateusz Sokół a0263ab472
Add `row_stack` to NumPy 2.0 migration rule (#10646)
Hi! 

I left out one of the functions in the migration rule which became
deprecated/removed in NumPy 2.0
(https://github.com/numpy/numpy/issues/26032#issuecomment-1999870797).

cc @anntzer
2024-03-28 09:49:40 -04:00
Jane Lewis 6b580c1544
Support unused code formatting for `ruff server` (#10644)
## Summary

Fixes #10589.

Code that violates `F401` or `F841` (in other words, unused variables or
imports) should now appear greyed out or 'unused' in an editor.

## Test Plan

Put the following test code in a new file within the extension
development host window:

```python
import math
def func():
   if False:
      unused = "<- this should be greyed out"
```

The following test code should have greyed out/unused import and
variable names, like so:
<img width="294" alt="Screenshot 2024-03-28 at 4 23 18 AM"
src="https://github.com/astral-sh/ruff/assets/19577865/e84a6e7a-49e2-4fed-9624-f8f9559e0837">
2024-03-28 11:30:35 +00:00
Jane Lewis 3f7d666e8b
`ruff server` now highlights most issues as warnings (#10643)
## Summary

Fixes #10588.

Most diagnostics from `ruff server` now appear as a much less alarming
warning instead of an error. Three diagnostics still appear as errors:
`F821` (`undefined name <name>`), `E902` (`IOError`) and `E999`
(`SyntaxError`).

## Test Plan

With an extension using the path to a locally-built executable, open a
file with multiple highlighted problems. Toggle the `Experimental
Server` setting on and off. The highlights should stay as warnings.

Then, modify the file to have a syntactically incorrect element. The
start of the invalid syntax should now have a red highlight.
2024-03-28 04:14:17 -07:00
Mix cce25ec116
Update warning message for rule S305 to address insecure block cipher mode use (#10602)
<!--
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 updates the warning message for rule S305 to accurately reflect
the security concern over using ECB mode in block ciphers, which is
considered insecure compared to other modes like CBC or CTR. The
previous message incorrectly mentioned AES as a [block cipher
mode](https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation),
which has been corrected to avoid confusion.

Ref: 

c85576d903/bandit/blacklists/calls.py (L99-L102)


825fd7c990/crates/ruff_linter/src/rules/flake8_bandit/rules/suspicious_function_call.rs (L187-L216)

## Test Plan

No testing required as the change is limited to a minor change of
warning message update.
2024-03-27 21:00:49 -04:00
Peter A. Jonsson fc7fa59e5f
space_around_operator: use same before/after numbers (#10640)
## Summary

The example for tab-after-comma (E242):
```python
a = 4,\t5
```
Use instead:
```python
a = 4, 3
```
is confusing since both the whitespace and the numbers are changed.

Change so the examples use the same numbers before/after.

## Test Plan

Untested.
2024-03-27 19:31:19 -04:00
Alex Waygood abbefae6f1
`DTZ` rules: Clarify error messages and docs (#10621)
- Clearly state in the documentation that passing `tz=None` is just as bad as not passing a `tz=` argument, from the perspective of these rules.
- Clearly state in the error messages exactly what the user is doing wrong, if the user is passing `tz=None` rather than failing to pass a `tz=` argument at all.
- Make error messages more concise, and separate out the suggested remedy from the thing that the user is identified as doing wrong.

Co-authored-by: Christian Clauss <cclauss@me.com>
2024-03-27 19:42:13 +00:00
Aleksei Latyshev f9d0c6d9ae
[`refurb`] Implement `for-loop-set-mutations` (`FURB142`) (#10583)
Co-authored-by: Alex Waygood <alex.waygood@gmail.com>
2024-03-27 09:26:12 +01:00
Jane Lewis 4d59142255
Client request sender and inbound response handling for `ruff server` (#10620)
## Summary

Fixes #10618.

This PR introduces a proper API for sending requests to the client and
handling any response sent back. Dynamic capability registration now
uses this new API, fixing an issue where a much more simplistic response
handler silently flushes a code action request that needed a response.

## Test Plan

#10618 can no longer be reproduced. No errors about unhandled responses
should appear in the extension output, and you should see this new log
when the server starts:
```
<DATE> <TIME> [info] <DURATION> INFO ruff_server::server Configuration file watcher successfully registered
```
2024-03-26 13:53:56 -07:00
Micha Reiser b49b861b2d
Delete unused `Violation::explanation` method (#10600) 2024-03-26 12:35:27 +01:00
Jane Lewis 825fd7c990
High-level project overview and contributing guide for `ruff server` (#10565)
## Summary

This PR adds an overview and roadmap to the `README.md` for the
`ruff_server` crate along with a rudimentary `CONTRIBUTING.md` that
explains some of the technical decisions behind the project and basic
information about local testing.
2024-03-25 23:08:37 -07:00
hikaru-kajita a28776e3aa
[`flake8-comprehensions`] Handled special case for `C401` which also matches `C416` (#10596)
## Summary

<!-- What's the purpose of the change? What does it do, and why? -->

Similar to #10419, there was a case where there is a collision of C401
and C416 (as discussed in #10101).
Fixed this by implementing short-circuit for the comprehension of the
form `{x for x in foo}`.

## Test Plan

<!-- How was it tested? -->

Extended `C401.py` with the case where `set` is not builtin function,
and divided the case where the short-circuit should occur.
Removed the last testcase of `print(f"{ {set(a for a in 'abc')} }")`
test as this is invalid as a python code, but should I keep this?
2024-03-26 03:54:58 +00:00
Aurelio Jargas 80b46889ed
Fix list markup: blank line required (#10591)
Judging from the other lists in this same file, it looks like a blank
line is required to separate the previous paragraph from the first list
item.

Otherwise the list is considered part of the paragraph:

- https://docs.astral.sh/ruff/settings/#lint_flake8-copyright_notice-rgx

<img width="400" alt="image"
src="https://github.com/astral-sh/ruff/assets/282592/663fa5b4-f787-4fcd-bdd6-0b891d7ad72b">

- https://docs.astral.sh/ruff/settings/#format_quote-style

<img width="400" alt="image"
src="https://github.com/astral-sh/ruff/assets/282592/809735eb-c546-4348-9311-877441bae84e">

After this change hopefully those will be rendered as proper bullet
lists.
2024-03-26 00:18:35 +00:00
Filipe Laíns 960e47423c
Put flake8-logging next to the other flake8 plugins in registry (#10587)
## Summary

This is just a nitpicky improvement, but I thought it'd be a good
opportunity to look at the ruff source.

> The rules list in the documentation is generated using the registry
order. Currently, flake8-logging is separated from the rest of the
flake8 plugins. This patch puts it next to them.

https://docs.astral.sh/ruff/rules/

If it makes sense, we could alternatively just sort the linters in
https://github.com/astral-sh/ruff/blob/main/crates/ruff_dev/src/generate_rules_table.rs.

Signed-off-by: Filipe Laíns <lains@riseup.net>
2024-03-25 20:23:31 +00:00
Dhruv Manilawala 4950ca4142
Ignore `Q000`, `Q001` when string is inside forward ref (#10585)
## Summary

This is not the holistic solution but just to fix that issue.

fixes: #10546 

## Test Plan

Add a regression test for it and check the snapshots.
2024-03-25 18:52:59 +00:00
hikaru-kajita f7aab5ac69
[`pylint`] Fixed false-positive on the rule `PLW1641` (`eq-without-hash`) (#10566)
## Summary

Fixed false-positive on the rule `PLW1641`, where the explicit
assignment on the `__hash__` method is not counted as an definition of
`__hash__`. (Discussed in #10557).

Also, added one new testcase.

## Test Plan

Checked on `cargo test` in `eq_without_hash.py`.

Before the change, for the assignment into `__hash__`, only `__hash__ =
None` was counted as an explicit definition of `__hash__` method.
Probably any assignment into `__hash__` property could be counted as an
explicit definition of hash, so I removed `value.is_none_literal_expr()`
check.
2024-03-25 14:40:01 +00:00
Hoël Bagard 9512bd66b5
[`pycodestyle`] Avoid blank line rules for the first logical line in cell (#10291)
## Summary

Closes #10228

The PR makes the blank lines rules keep track of the cell status when
running on a notebook, and makes the rules not trigger when the line is
the first of the cell.

## Test Plan

The example given in #10228 is added as a fixture, along with a few
tests from the main blank lines fixtures.
2024-03-25 11:19:30 +00:00
Dhruv Manilawala e9115b8d8a
Move `Q004` to AST based checker (#10548)
## Summary

Continuing with #7595, this PR moves the `Q004` rule to the AST checker.

## Test Plan

- [x] Existing test cases should pass
- [x] No ecosystem updates
2024-03-25 03:31:31 +00:00
Alexey Preobrazhenskiy d625f55c05
Nested namespace packages support (#10541)
## Summary
PEP 420 says [nested namespace
packages](https://peps.python.org/pep-0420/#nested-namespace-packages)
are allowed, i.e. marking a directory as a namespace package marks all
subdirectories in the subtree as namespace packages.

`is_package` is modified to use `Path::starts_with` and the order of
checks is reversed to do in-memory checks first before hitting the disk.

## Test Plan
Added unit tests. Previously all tests were run with `namespace_packages
== &[]`. Verified that one of the tests was failing before changing the
implementation.

## Future Improvements
The `is_package_with_cache` can probably be rewritten to avoid repeated
calls to `Path::starts_with`, by caching all directories up to the
`namespace_root`:
```ruff
let namespace_root = namespace_packages
    .iter()
    .filter(|namespace_package| path.starts_with(namespace_package))
    .min();
```
2024-03-24 22:53:32 -04:00
Charlie Marsh 9856c1446b
Document use of anonymous assignment in `useless-expression` (#10551)
Closes https://github.com/astral-sh/ruff/issues/10536.
2024-03-25 02:46:33 +00:00
hikaru-kajita 39fb6d9bfc
[`refurb`] Implement `verbose-decimal-constructor` (`FURB157`) (#10533)
## Summary

Implement FURB157 in the issue #1348.
Relevant Refurb docs is here:
https://github.com/dosisod/refurb/blob/master/docs/checks.md#furb157-simplify-decimal-ctor

## Test Plan

I've written it in the `FURB157.py`.
2024-03-24 22:28:58 -04:00
yt2b 22f237fec6
[`flake8-bugbear`] Avoid false positive for usage after `continue` (`B031`) (#10539)
## Summary

Closes #10337.

I've fixed the code to count usage of variable.
Usage count inside the block is reset when there is a following
statement.
- continue
- break
- return 

## Test Plan

Add test case.
2024-03-25 00:38:30 +00:00
Alex Waygood 021f0bdccb
Mark PYI025 fix as safe in more cases for stub files (#10547)
## Summary

The fix for PYI025 is currently marked as unsafe in non-global scopes
for both `.py` and `.pyi` files, on the grounds that all global-scope
symbols in Python are implicitly exported from the module, so changing
the name of something in the global scope could break other modules that
import the module we're fixing. Unlike in `.py` files, however, imported
symbols are never implicitly re-exported from stub files. Symbols are
only understood by static analysis tools as being re-exported from stubs
if they are marked as explicit re-exports, which take three forms:

```py
from foo import *  # all symbols from foo are re-exported from the stub

# the "redundant" alias marks it as an explicit re-export
# (note that the alias needs to be identical to the symbol's "actual" name
# in order for it to be a re-export)
from bar import barrr as barrr

# inclusion in __all__ also marks it as an explicit re-export,
# just like in `.py` files
from baz import bazzz
__all__ = ["bazzz"]
```

This is [specc'd in PEP
484](https://peps.python.org/pep-0484/#stub-files), and means that we
can mark the fix for PYI025 as safe in more cases for `.pyi` files.

## Test Plan

`cargo test`. An existing test case goes from being an unsafe fix to a
safe fix in a `.pyi` fixture. I also added a new fixture so we have
coverage of global-scope imports that are marked as re-exports using
"redundant" `from collections.abc import Set as Set` aliases.
2024-03-24 16:11:48 +00:00
Alexey Preobrazhenskiy 7cc40d5621
Refactor `package_roots` for readability. (#10543) 2024-03-24 12:02:30 +00:00
Dhruv Manilawala c447454111
[`E402`] Allow cell magics before an import (#10545) 2024-03-24 16:20:00 +05:30
Dhruv Manilawala 895d9df02f
Move `Q001-3` to AST based checker (#10312)
## Summary

Continuing with https://github.com/astral-sh/ruff/issues/7595, this PR
moves the `Q001`, `Q002`, `Q003` rules to the AST based checker.

## Test Plan

Make sure all of the existing test cases pass and verify there are no
ecosystem changes.
2024-03-23 22:59:50 +05:30
Auguste Lalande 0c194f55e8
Fix `PT014` autofix for last item in list (#10532)
## Summary

This error was found browsing
https://github.com/qarmin/Automated-Fuzzer/actions/runs/8396966850.
Which failed when trying to autofix the PT014 violation in the following
code:
```python
@pytest.mark.parametrize('data, spec', [(1.0, 1.0), (1.0, 1.0)])
def test_numbers(data, spec):
    ...
```

Investigation revealed that the implementation was not properly tested,
when the duplicate value was also the last in the list. In particular
the following function, which is in charge of finding the comma
following an element to create the suggested fix,

0a99bd84ce/crates/ruff_linter/src/rules/flake8_pytest_style/rules/parametrize.rs (L647-L651)
would find the next comma even if it was outside the list itself leading
to a lot of code being deleted.

This PR fixes that.

## Test Plan

Added misbehaving code to the test fixture.
2024-03-23 09:26:42 -04:00
Alex Waygood 9feb9b0aa8
Correctly handle references in `__all__` definitions when renaming symbols in autofixes (#10527) 2024-03-22 20:06:35 +00:00
Charlie Marsh 61b7982422
Respect Unicode characters in import sorting (#10529)
## Summary

Ensures that we use the raw identifier as provided in the source code,
rather than the normalized Unicode identifier.

This _does_ mean that we treat these as two separate identifiers, and
_don't_ merge them, even though Python will treat them as the same
symbol:

```python
import numpy as ℂℇℊℋℌℍℎℐℑℒℓℕℤΩℨKÅℬℭℯℰℱℹℴ
import numpy as CƐgHHHhIILlNZΩZKÅBCeEFio
```

I think that's fine, this is super rare anyway and would likely be
confusing for users.

Closes https://github.com/astral-sh/ruff/issues/10528.

## Test Plan

`cargo test`
2024-03-22 15:16:49 -04:00
Ryan May 594b232e0f
Accept commas in default copyright pattern (#9498)
## Summary

Adds commas as an accepted separator between copyright years by default,
which is actually documented in one spot, but not currently accurate.
Fixes #9477.
2024-03-22 14:42:02 -04:00
Alex Waygood a06ffeb54e
Track ranges of names inside `__all__` definitions (#10525) 2024-03-22 18:38:40 +00:00
Alex Waygood b74dd420fc
Fix F821 false negatives when `from __future__ import annotations` is active (attempt 2) (#10524) 2024-03-22 18:11:16 +00:00
Jane Lewis 4f06d59ff6
Automatic configuration reloading for `ruff server` (#10404)
## Summary

Fixes #10366.

`ruff server` now registers a file watcher on the client side using the
LSP protocol, and listen for events on configuration files. On such an
event, it reloads the configuration in the 'nearest' workspace to the
file that was changed.

## Test Plan

N/A
2024-03-21 20:17:07 +00:00
Charlie Marsh 5062572aca
Bump version to v0.3.4 (#10515) 2024-03-21 18:08:21 +00:00
Charlie Marsh dc6f6398e7
Rename `list-reassign-reversed` to `list-reverse-copy` (#10514)
After discussion with @MichaReiser.
2024-03-21 17:33:00 +00:00
Aleksei Latyshev 01fe268612
[`refurb`] Implement `list_assign_reversed` lint (FURB187) (#10212)
## Summary

Implement [use_reverse
(FURB187)](https://github.com/dosisod/refurb/blob/master/refurb/checks/readability/use_reverse.py)
lint.
Tests were copied from original
https://github.com/dosisod/refurb/blob/master/test/data/err_187.py.

## Test Plan

cargo test
2024-03-21 17:09:09 +00:00
Alex Waygood c62184d057
'Revert "F821: Fix false negatives in .py files when `from __future__ import annotations` is active (#10362)"' (#10513) 2024-03-21 16:41:05 +00:00
Auguste Lalande 9b3c732538
Docs: Link inline settings when not part of options section (#10499)
## Summary
 
Some contributors have referenced settings in their documentation
without adding the settings to an options section, this has lead to some
rendering issues (#10427). This PR addresses this looking for potential
inline links to settings, cross-checking them with the options sections,
and then linking them anyway if they are not found.

Resolves #10427.

## Test Plan

Manually verified that the correct modifications were made and no docs
were broken.
2024-03-21 16:33:58 +00:00
Charlie Marsh caa1450895
Don't treat annotations as redefinitions in `.pyi` files (#10512)
## Summary

In https://github.com/astral-sh/ruff/pull/10341, we fixed some false
positives in `.pyi` files, but introduced others. This PR effectively
reverts the change in #10341 and fixes it in a slightly different way.
Instead of changing the _bindings_ we generate in the semantic model in
`.pyi` files, we instead change how we _resolve_ them.

Closes https://github.com/astral-sh/ruff/issues/10509.
2024-03-21 12:22:50 -04:00
Charlie Marsh 60fd98eb2f
Update Rust to v1.77 (#10510) 2024-03-21 12:10:33 -04:00
Alex Waygood ac150b9314
Spruce up docs for flake8-pyi rules (part 2) (#10494)
- Improve clarity over the motivation for some rules
- Improve links to external references. In particular, reduce links to PEPs, as PEPs are generally historical documents rather than pieces of living documentation. Where possible, it's better to link to the official typing spec, the other docs at typing.readthedocs.io/en/latest, or the docs at docs.python.org/3/library/typing.html.
- Use more concise language in a few places
2024-03-21 11:54:43 +00:00
Auguste Lalande d9ac170eb4
Fix `E231` bug: Inconsistent catch compared to pycodestyle, such as when dict nested in list (#10469)
<!--
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

Fix `E231` bug: Inconsistent catch compared to pycodestyle, such as when
dict nested in list. Resolves #10113.

## Test Plan

Example from #10113 added to test fixture.
2024-03-21 09:13:37 +01:00
veryyet c5ea4209bb
chore: remove repetitive words (#10502) 2024-03-21 03:57:16 +00:00
Charlie Marsh 9aded0284e
Add missing `Options` references to blank line docs (#10498)
See: https://github.com/astral-sh/ruff/issues/10427.
2024-03-21 00:49:36 +00:00
Auguste Lalande 685de912ff
[`pylint`] Implement `nan-comparison` (`PLW0117`) (#10401)
## Summary

Implement pylint's nan-comparison, part of #970.

## Test Plan

Text fixture was added.
2024-03-21 00:36:17 +00:00
Sergey Chudov 4045df4ad4
Avoid incorrect tuple transformation in single-element case (`C409`) (#10491)
# Summary
Fixed: incorrect rule transformation rule C409 with single element.

# Test Plan
Added examples from #10323 to test fixtures.
2024-03-21 00:09:28 +00:00
Micha Reiser 9d705a4414
Fix subscript comment placement with parenthesized value (#10496)
## Summary

This is a follow up on https://github.com/astral-sh/ruff/pull/10492 

I incorrectly assumed that `subscript.value.end()` always points past
the value. However, this isn't the case for parenthesized values where
the end "ends" before the parentheses.

## Test Plan

I added new tests for the parenthesized case.
2024-03-20 20:30:22 +00:00
Auguste Lalande fd3d272026
Improve clarity of `PT006`'s error message (#10468)
Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
2024-03-20 18:22:02 +00:00
Micha Reiser 954a48b129
Fix instable formatting for trailing subscribt end-of-line comment (#10492)
## Summary

This PR fixes an instability where formatting a subscribt 
where the `slice` is not an `ExprSlice` and it has a trailing
end-of-line comment after its opening `[` required two formatting passes
to be stable.

The fix is to associate the trailing end-of-line comment as dangling
comment on `[` to preserve its position, similar to how Ruff does it for
other parenthesized expressions.
This also matches how trailing end-of-line subscript comments are
handled when the `slice` is an `ExprSlice`.

Fixes https://github.com/astral-sh/ruff/issues/10355

## Versioning

Shipping this as part of a patch release is fine because:

* It fixes a stability issue
* It doesn't impact already formatted code because Ruff would already
have moved to the comment to the end of the line (instead of preserving
it)

## Test Plan

Added tests
2024-03-20 18:12:10 +01:00
Alex Waygood 7caf0d064a
Simplify formatting of strings by using flags from the AST nodes (#10489) 2024-03-20 16:16:54 +00:00
Vasco Schiavo fc792d1d2e
Fix error message for rule C400 (#10488)
Fix a typos in the error message of rule C400

With the latest version of Ruff (0.3.3) if I have a `scratch.py` script
like that:

```python
from typing import Dict, List, Tuple


def generate_samples(test_cases: Dict) -> List[Tuple]:
    return list(
        (input, expected)
        for input, expected in zip(test_cases["input_value"], test_cases["expected_value"])
    )
```

and I run ruff

```shell
>>> ruff check scratch.py --select C400
>>> scratch.py:5:12: C400 Unnecessary generator (rewrite using `list()`
```

This PR fixes the error message from _"(rewrite using `list()`"_ to
_"(rewrite using `list()`)"_, and it fixes also the doc.

Related question: why I have this error message? The rule is not correct
in this case. Should I open an issue for that?
2024-03-20 14:22:34 +01:00
Charlie Marsh f7740a8a20
Allow SPDX license headers to exceed the line length (#10481)
Closes https://github.com/astral-sh/ruff/issues/10465.
2024-03-19 15:57:03 -04:00
Dhruv Manilawala 42d4216fd7
Consider raw source code for `W605` (#10480)
## Summary

This PR fixes a panic in the linter for `W605`.

Consider the following f-string:
```python
f"{{}}ab"
```

The `FStringMiddle` token would contain `{}ab`. Notice that the escaped
braces have _reduced_ the string. This means we cannot use the text
value from the token to determine the location of the escape sequence
but need to extract it from the source code.

fixes: #10434 

## Test Plan

Add new test cases and update the snapshots.
2024-03-20 00:16:35 +05:30
Charlie Marsh bc9b4571eb
Avoid failures due to non-deterministic binding ordering (#10478)
## Summary

We're seeing failures in https://github.com/astral-sh/ruff/issues/10470
because `resolve_qualified_import_name` isn't guaranteed to return a
specific import if a symbol is accessible in two ways (e.g., you have
both `import logging` and `from logging import error` in scope, and you
want `logging.error`). This PR breaks up the failing tests such that the
imports aren't in the same scope.

Closes https://github.com/astral-sh/ruff/issues/10470.

## Test Plan

I added a `bindings.reverse()` to `resolve_qualified_import_name` to
ensure that the tests pass regardless of the binding order.
2024-03-19 18:01:33 +00:00
Alex Waygood ffd6e79677
Fix typo in `string_token_flags.rs` (#10476) 2024-03-19 17:43:08 +00:00
Micha Reiser 17d56ccab3
Remove unused dependencies (#10475)
## Summary
I used `cargo-shear` (see
[tweet](https://twitter.com/boshen_c/status/1770106165923586395)) to
remove some unused dependencies that `cargo udeps` wasn't reporting.

<!-- What's the purpose of the change? What does it do, and why? -->

## Test Plan

`cargo test`
2024-03-19 17:33:47 +01:00
Auguste Lalande 363ff2a87e
Clarify `extend-select` documentation (#10467)
<!--
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

Clarify `extend-select` documentation to avoid confusion regarding the
default `select`. Also match the `select` documentation. Resolves
#10389.

## Test Plan

<!-- How was it tested? -->
2024-03-19 09:51:31 +01:00
Charlie Marsh 938118b65c
Avoid code comment detection in PEP 723 script tags (#10464)
Closes https://github.com/astral-sh/ruff/issues/10455.
2024-03-18 17:48:51 -04:00
Jane Lewis d9f1cdbea1
`ruff server` sets worker thread pool size based on the user's available cores (#10399)
## Summary

Fixes #10369.

## Test Plan

N/A
2024-03-18 14:06:59 -07:00
Sid 1a2f9f082d
[`flake8-pytest-style`] Add automatic fix for `pytest-parametrize-values-wrong-type` (`PT007`) (#10461)
## Summary

This adds automatic fixes for the `PT007` rule.

I am currently reviewing and adding Ruff rules to Home Assistant. One
rule is PT007, which has multiple hundred occurrences in the codebase,
but no automatic fix, and this is not fun to do manually, especially
because using Regexes are not really possible with this.

My knowledge of the Ruff codebase and Rust in general is not good and
this is my first PR here, so I hope it is not too bad.

One thing where I need help is: How can I have the transformed code to
be formatted automatically, instead of it being minimized as it does it
now?

## Test Plan

Using the existing fixtures and updated snapshots.
2024-03-18 20:28:49 +00:00
Alex Waygood ae0ff9b029
Spruce up docs for flake8-pyi rules (#10422) 2024-03-18 18:03:32 +00:00
Alex Waygood 162d2eb723
Track casing of r-string prefixes in the tokenizer and AST (#10314)
Co-authored-by: Micha Reiser <micha@reiser.io>
2024-03-18 17:18:04 +00:00
Micha Reiser 31db1b6e16
Remove long `Iterator::chain` sequence in `RuleCodePrefix::iter` (#10452)
## Summary

This PR removes the `Iterator::chain(...)` sequence in
`RuleCodePrefix::iter()` with `Vec::expand` to avoid an
overlong-recursive types.

The existing `RuleCodePrefix::iter` method chains all rule group
iterators together. This leads to very long recursive types
`Chain<Map<Chain<Map<Chain<Map.....>>>>` (proportional to the number of
rule groups).

This PR rewrites the macro to use `Vec::extend` instead, which removes
the long recursive type (at the cost of introducing a potential
allocation).

## Alternatives

An alternative would be to use a stack allocated array by unrolling the
`Linter::iter` methods (generated by `EnumIter`).
I don't think it's worth the extra complexity, considering that
`RuleCodePrefix::iter` isn't a hot function.

## Test Plan

`cargo test`
2024-03-18 16:51:20 +01:00
Jane Lewis 93566f9321
`ruff server` default to current working directory in environments without any root directories or workspaces (#10398)
## Summary

Fixes #10324

This removes an overeager failure case where we would exit early if no
root directory or workspace folders were provided on server
initialization. We now fall-back to the current working directory as a
workspace for that file.

## Test Plan
N/A
2024-03-18 08:46:44 -07:00
Alex Waygood 92e6026446
Apply NFKC normalization to unicode identifiers in the lexer (#10412) 2024-03-18 11:56:56 +00:00
Micha Reiser 12486315fb
Move deviations from formatter README to documentation (#10444)
## Summary

#10151 documented the deviations between Ruff and Black with the new
2024 style guide in the `ruff-python-formatter/README.md`. However,
that's not the documentation shown
on the website when navigating to [intentional
deviations](https://docs.astral.sh/ruff/formatter/black/).

This PR streamlines the `ruff-python-formatter/README.md` and links to
the documentation on the website instead of repeating the same content.
The PR also makes the 2024 style guide deviations available on the
website documentation.

## Test Plan

I built the documentation locally and verified that the 2024 style guide
known deviations are now shown on the website.
2024-03-18 08:22:28 +00:00
Auguste Lalande 91e81413db
Bug fix: Prevent fully defined links [``name``](link) from being reformatted (#10442)
## Summary

Currently fully define markdown links which include ticks are being
reformatted by

8619986123/crates/ruff_dev/src/generate_docs.rs (L105-L114)

```[`name`](link)``` -> ```[`name`][name](link)```

For example: https://docs.astral.sh/ruff/rules/typed-argument-default-in-stub/

This PR excludes the open parentheses from the regex, so that these types of links won't be reformatted.

## Test Plan

Extended the regression test.
2024-03-17 22:01:30 -04:00
Robin Caloudis 2edd61709f
[`flake8-quotes`] Fix Autofix Error (`Q000, Q002`) (#10199)
## Summary
In issue https://github.com/astral-sh/ruff/issues/6785 it is reported
that a docstring in the form of `''"assert" ' SAM macro definitions '''`
is autocorrected to `"""assert" ' SAM macro definitions '''` (note the
triple quotes one only one side), which breaks the python program due
`undetermined string lateral`.

* `Q002`: Not only would docstrings in the form of `''"assert" ' SAM
macro definitions '''` (single quotes) be autofixed wrongly, but also
e.g. `""'assert' ' SAM macro definitions '''` (double quotes). The bug
is present for docstrings in all scopes (e.g. module docstrings, class
docstrings, function docstrings)

* `Q000`: The autofix error is not only present for `Q002` (docstrings),
but also for inline strings (`Q000`). Therefore `s = ''"assert" ' SAM
macro definitions '''` will also be wrongly autofixed.

Note that situation in which the first string is non-empty can be fixed,
e.g. `'123'"assert" ' SAM macro definitions '''` -> `"123""assert" ' SAM
macro definitions '''` is valid.

## What
* Change FixAvailability of `Q000` `Q002` to `Sometimes`
* Changed both rules such that docstrings/inline strings that cannot be
fixed are still reported as bad quotes via diagnostics, but no fix is
provided

## Test Plan
* For `Q000`: Add docstrings in different scopes that (partially) would
have been autofixed wrongly
* For `Q002`: Add inline strings that (partially) would have been
autofixed wrongly

Closes https://github.com/astral-sh/ruff/issues/6785
2024-03-18 01:31:25 +00:00
Auguste Lalande dc021dd4d2
Fix pylint upstream categories not showing in docs (#10441)
## Summary

The upstream category check here

fd26b29986/crates/ruff_linter/src/upstream_categories.rs (L54-L65)

was not working because the code is actually "E0001" not "PLE0001", I
changed it so it will detect the upstream category correctly.

I also sorted the upstream categories alphabetically, so that the
document generation will be deterministic.

## Test Plan

I compared the diff before and after the change.
2024-03-18 01:27:39 +00:00
hikaru-kajita fd26b29986
[`pylint`] Implement `nonlocal-and-global` (`E115`) (#10407)
## Summary

Implement `E115` in the issue #970.
Reference to pylint docs:
https://pylint.readthedocs.io/en/stable/user_guide/messages/error/nonlocal-and-global.html
Throws an error when a variable name is both declared as global and
nonlocal

## Test Plan

With `nonlocal_and_global.py`
2024-03-18 00:43:02 +00:00
Ottavio Hartman 6123a5b8bc
[`flake8-bugbear`] Allow tuples of exceptions (`B030`) (#10437)
Fixes #10426 

## Summary

Fix rule B030 giving a false positive with Tuple operations like `+`.

[Playground](https://play.ruff.rs/17b086bc-cc43-40a7-b5bf-76d7d5fce78a)
```python
try:
    ...
except (ValueError,TypeError) + (EOFError,ArithmeticError):
    ...
```

## Reviewer notes

This is a little more convoluted than I was expecting -- because we can
have valid nested Tuples with operations done on them, the flattening
logic has become a bit more complex.

Shall I guard this behind --preview?

## Test Plan

Unit tested.
2024-03-18 00:31:23 +00:00
Ottavio Hartman 526abebbae
[`flake8-simplify`] Detect implicit `else` cases in `needless-bool` (`SIM103`) (#10414)
Fixes #10402 

## Summary

For SIM103, detect and simplify the following case:

[playground
link](https://play.ruff.rs/d98570aa-b180-495b-8600-5c4c3fd02526)
```python
def main():
    if foo > 5:
        return True
    return False
```

## Test Plan

Unit tested only.
2024-03-18 00:15:28 +00:00
Auguste Lalande 229a50a2c8
[`pylint`] Implement `singledispatchmethod-function` (`PLE5120`) (#10428)
## Summary

Implement `singledispatchmethod-function` from pylint, part of #970.

This is essentially a copy paste of #8934 for `@singledispatchmethod`
decorator.

## Test Plan

Text fixture added.
2024-03-18 00:02:52 +00:00
Zanie Blue 608df9a1bc
Bump version to 0.3.3 (#10425)
Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
2024-03-15 12:51:49 -05:00
Steve C 740c08b033
[`pylint`] - implement `redeclared-assigned-name` (`W0128`) (#9268)
## Summary

Implements
[`W0128`/`redeclared-assigned-name`](https://pylint.readthedocs.io/en/latest/user_guide/messages/warning/redeclared-assigned-name.html)

See: #970 

## Test Plan

`cargo test`
2024-03-15 09:43:55 -05:00
hikaru-kajita 7e652e8fcb
[`flake8_comprehensions`] Handled special case for `C400` which also matches `C416` (#10419)
## Summary

Short-circuit implementation mentioned in #10403.

I implemented this by extending C400:
- Made `UnnecessaryGeneratorList` have information of whether the the
short-circuiting occurred (to put diagnostic)
- Add additional check for whether in `unnecessary_generator_list`
function.

Please give me suggestions if you think this isn't the best way to
handle this :)

## Test Plan

Extended `C400.py` a little, and written the cases where:
- Code could be converted to one single conversion to `list` e.g.
`list(x for x in range(3))` -> `list(range(3))`
- Code couldn't be converted to one single conversion to `list` e.g.
`list(2 * x for x in range(3))` -> `[2 * x for x in range(3)]`
- `list` function is not built-in, and should not modify the code in any
way.
2024-03-15 14:34:18 +00:00
Tom Kuson 9675e1867a
Allow trailing ellipsis in `typing.TYPE_CHECKING` (#10413)
## Summary

Trailing ellipses in objects defined in `typing.TYPE_CHECKING` might be
meaningful (it might be declaring a stub). Thus, we should skip the
`unnecessary-placeholder` (`PIE970`) rule in such contexts.

Closes #10358.

## Test Plan

`cargo nextest run`
2024-03-15 03:55:57 +00:00
Charlie Marsh 10ace88e9a
Track conditional deletions in the semantic model (#10415)
## Summary

Given `del X`, we'll typically add a `BindingKind::Deletion` to `X` to
shadow the current binding. However, if the deletion is inside of a
conditional operation, we _won't_, as in:

```python
def f():
    global X

    if X > 0:
        del X
```

We will, however, track it as a reference to the binding. This PR adds
the expression context to those resolved references, so that we can
detect that the `X` in `global X` was "assigned to".

Closes https://github.com/astral-sh/ruff/issues/10397.
2024-03-14 20:45:46 -04:00
Guilherme Vasconcelos a8e50a7f40
[RUF008] Make it clearer that a mutable default in a dataclass is only valid if it is typed as a ClassVar (#10395)
## Summary

The previous documentation sounded as if typing a mutable default as a
`ClassVar` were optional. However, it is not, as not doing so causes a
`ValueError`. The snippet below was tested in Python's interactive
shell:

```
>>> from dataclasses import dataclass
>>> @dataclass
... class A:
...     mutable_default: list[int] = []
... 
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python3.11/dataclasses.py", line 1230, in dataclass
    return wrap(cls)
           ^^^^^^^^^
  File "/usr/lib/python3.11/dataclasses.py", line 1220, in wrap
    return _process_class(cls, init, repr, eq, order, unsafe_hash,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/dataclasses.py", line 958, in _process_class
    cls_fields.append(_get_field(cls, name, type, kw_only))
                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/dataclasses.py", line 815, in _get_field
    raise ValueError(f'mutable default {type(f.default)} for field '
ValueError: mutable default <class 'list'> for field mutable_default is not allowed: use default_factory
>>>
```

This behavior is also documented in Python's docs, see
[here](https://docs.python.org/3/library/dataclasses.html#mutable-default-values):

> [...] the
[dataclass()](https://docs.python.org/3/library/dataclasses.html#dataclasses.dataclass)
decorator will raise a
[ValueError](https://docs.python.org/3/library/exceptions.html#ValueError)
if it detects an unhashable default parameter. The assumption is that if
a value is unhashable, it is mutable. This is a partial solution, but it
does protect against many common errors.

And
[here](https://docs.python.org/3/library/dataclasses.html#class-variables)
it is documented why it works if it is typed as a `ClassVar`:

> One of the few places where
[dataclass()](https://docs.python.org/3/library/dataclasses.html#dataclasses.dataclass)
actually inspects the type of a field is to determine if a field is a
class variable as defined in [PEP
526](https://peps.python.org/pep-0526/). It does this by checking if the
type of the field is typing.ClassVar. If a field is a ClassVar, it is
excluded from consideration as a field and is ignored by the dataclass
mechanisms. Such ClassVar pseudo-fields are not returned by the
module-level
[fields()](https://docs.python.org/3/library/dataclasses.html#dataclasses.fields)
function.

In this PR I have changed the documentation to make it a little bit
clearer that not using `ClassVar` makes the code invalid.
2024-03-14 23:18:03 +00:00
Hoël Bagard e944c16c46
[`pycodestyle`] Do not ignore lines before the first logical line in blank lines rules (#10382)
## Summary

Ignoring all lines until the first logical line does not match the
behavior from pycodestyle. This PR therefore removes the `if
state.is_not_first_logical_line` skipping the line check before the
first logical line, and applies it only to `E302`.

For example, in the snippet below a rule violation should be detected on
the second comment and on the import.

```python
# first comment




# second comment




import foo
```

Fixes #10374

## Test Plan

Add test cases, update the snapshots and verify the ecosystem check output
2024-03-14 14:05:24 +05:30
Dhruv Manilawala 5f40371ffc
Use `ExprFString` for `StringLike::FString` variant (#10311)
## Summary

This PR updates the `StringLike::FString` variant to use `ExprFString`
instead of `FStringLiteralElement`.

For context, the reason it used `FStringLiteralElement` is that the node
is actually the string part of an f-string ("foo" in `f"foo{x}"`). But,
this is inconsistent with other variants where the captured value is the
_entire_ string.

This is also problematic w.r.t. implicitly concatenated strings. Any
rules which work with `StringLike::FString` doesn't account for the
string part in an implicitly concatenated f-strings. For example, we
don't flag confusable character in the first part of `"𝐁ad" f"𝐁ad
string"`, but only the second part
(https://play.ruff.rs/16071c4c-a1dd-4920-b56f-e2ce2f69c843).

### Update `PYI053`

_This is included in this PR because otherwise it requires a temporary
workaround to be compatible with the old logic._

This PR also updates the `PYI053` (`string-or-bytes-too-long`) rule for
f-string to consider _all_ the visible characters in a f-string,
including the ones which are implicitly concatenated. This is consistent
with implicitly concatenated strings and bytes.

For example,

```python
def foo(
	# We count all the characters here
    arg1: str = '51 character ' 'stringgggggggggggggggggggggggggggggggg',
	# But not here because of the `{x}` replacement field which _breaks_ them up into two chunks
    arg2: str = f'51 character {x} stringgggggggggggggggggggggggggggggggggggggggggggg',
) -> None: ...
```

This PR fixes it to consider all _visible_ characters inside an f-string
which includes expressions as well.

fixes: #10310 
fixes: #10307 

## Test Plan

Add new test cases and update the snapshots.

## Review

To facilitate the review process, the change have been split into two
commits: one which has the code change while the other has the test
cases and updated snapshots.
2024-03-14 13:30:22 +05:30
boolean f7802ad5de
[`pylint`] Extend docs and test in `invalid-str-return-type` (`E307`) (#10400)
## Summary

Added some docs, and a little of test cases in
`invalid-str-return-type`, mentioned in
https://github.com/astral-sh/ruff/pull/10377#pullrequestreview-1934295027

## Test Plan

On `invalid_return_type_str.py`.

---------

Co-authored-by: Dhruv Manilawala <dhruvmanila@gmail.com>
2024-03-14 04:38:30 +00:00
Jane Lewis e832327a56
Require --preview for `ruff server` (#10368)
## Summary

Fixes #10367.

While the server is still in an unstable state, requiring a `--preview`
flag would be a good way to indicate this to end users.
2024-03-13 23:52:44 +00:00
Charlie Marsh 324390607c
[`pylint`] Include builtin warnings in useless-exception-statement (`PLW0133`) (#10394)
## Summary

Closes https://github.com/astral-sh/ruff/issues/10392.
2024-03-13 15:26:11 -04:00
Tri Ho 4db5c29f19
Indicated Successful Check (#8631)
<!--
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

Adds a successful check message after no errors were found 
Implements #8553 

<!-- What's the purpose of the change? What does it do, and why? -->

## Test Plan

Ran a check on a test file with `cargo run -p ruff_cli -- check test.py
--no-cache` and outputted as expected.

Ran the same check with `cargo run -p ruff_cli -- check test.py
--no-cache --silent` and the command was gone as expected.

<!-- How was it tested? -->

---------

Co-authored-by: Zanie Blue <contact@zanie.dev>
2024-03-13 19:07:11 +00:00
Zanie Blue 7b3ee2daff
Remove `F401` fix for `__init__` imports by default and allow opt-in to unsafe fix (#10365)
Re-implementation of https://github.com/astral-sh/ruff/pull/5845 but
instead of deprecating the option I toggle the default. Now users can
_opt-in_ via the setting which will give them an unsafe fix to remove
the import. Otherwise, we raise violations but do not offer a fix. The
setting is a bit of a misnomer in either case, maybe we'll want to
remove it still someday.

As discussed there, I think the safe fix should be to import it as an
alias. I'm not sure. We need support for offering multiple fixes for
ideal behavior though? I think we should remove the fix entirely and
consider it separately.

Closes https://github.com/astral-sh/ruff/issues/5697
Supersedes https://github.com/astral-sh/ruff/pull/5845

---------

Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
2024-03-13 12:58:25 -05:00
Alex Waygood c2e15f38ee
Unify enums used for internal representation of quoting style (#10383) 2024-03-13 17:19:17 +00:00
Charlie Marsh d59433b12e
Avoid removing shadowed imports that point to different symbols (#10387)
This ensures that we don't have incorrect, automated fixes for shadowed
names that actually point to different imports.

See: https://github.com/astral-sh/ruff/issues/10384.
2024-03-13 15:44:28 +00:00
boolean c269c1a706
[`pylint`] Implement `invalid-bool-return-type` (`E304`) (#10377)
## Summary

Implement `E304` in the issue #970. Throws an error when the returning value
of `__bool__` method is not boolean.

Reference: https://pylint.readthedocs.io/en/stable/user_guide/messages/error/invalid-bool-returned.html

## Test Plan

Add test cases and run `cargo test`
2024-03-13 19:43:45 +05:30
Dhruv Manilawala 32d6f84e3d
Add methods to iter over f-string elements (#10309)
## Summary

This PR adds methods on `FString` to iterate over the two different kind
of elements it can have - literals and expressions. This is similar to
the methods we have on `ExprFString`.

---------

Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
2024-03-13 08:46:55 +00:00
Auguste Lalande 93d582d734
Avoid `TRIO115` if the argument is a variable (#10376)
## Summary

Fix "TRIO115 false positive with with sleep(var) where var starts as 0"
#9935 based on the discussion in the issue.

## Test Plan

Issue code added to fixture
2024-03-13 13:09:18 +05:30
Auguste Lalande 3ed707f245
Spellcheck & grammar (#10375)
## Summary

I used `codespell` and `gramma` to identify mispellings and grammar
errors throughout the codebase and fixed them. I tried not to make any
controversial changes, but feel free to revert as you see fit.
2024-03-13 02:34:23 +00:00
Charlie Marsh c56fb6e15a
Sort hash maps in `Settings` display (#10370)
## Summary

We had a report of a test failure on a specific architecture, and
looking into it, I think the test assumes that the hash keys are
iterated in a specific order. This PR thus adds a variant to our
settings display macro specifically for maps and sets. Like `CacheKey`,
it sorts the keys when printing.

Closes https://github.com/astral-sh/ruff/issues/10359.
2024-03-12 15:59:38 -04:00
Charlie Marsh dbf82233b8
Gate f-string struct size test for Rustc < 1.76 (#10371)
Closes https://github.com/astral-sh/ruff/issues/10319.
2024-03-12 15:46:36 -04:00
Zanie Blue 87afe36c87
Add test case for `F401` in `__init__` files (#10364)
In preparation for https://github.com/astral-sh/ruff/pull/5845
2024-03-12 13:30:17 -05:00
Alex Waygood 704fefc7ab
F821: Fix false negatives in `.py` files when `from __future__ import annotations` is active (#10362) 2024-03-12 17:07:44 +00:00
Auguste Lalande dacec7377c
Fix Indexer fails to identify continuation preceded by newline #10351 (#10354)
## Summary

Fixes #10351

It seems the bug was caused by this section of code

b669306c87/crates/ruff_python_index/src/indexer.rs (L55-L58)

It's true that newline tokens cannot be immediately followed by line
continuations, but only outside parentheses. e.g. the exception
```
(
    1
    \
    + 2)
```

But why was this check put there in the first place? Is it guarding
against something else?



## Test Plan

New test was added to indexer
2024-03-12 00:35:41 -04:00
Anuraag (Rag) Agrawal b669306c87
Fix typo in docs snippt -> snippet (#10353) 2024-03-11 22:33:40 -04:00
Auguste Lalande b117f33075
[`pycodestyle`] Implement `blank-line-at-end-of-file` (`W391`) (#10243)
## Summary

Implements the [blank line at end of
file](https://pycodestyle.pycqa.org/en/latest/intro.html#error-codes)
rule (W391) from pycodestyle. Renamed to TooManyNewlinesAtEndOfFile for
clarity.

## Test Plan

New fixtures have been added

Part of #2402
2024-03-11 22:07:59 -04:00
Auguste Lalande c746912b9e
[`pycodestyle`] Implement `redundant-backslash` (`E502`) (#10292)
## Summary

Implements the
[redundant-backslash](https://pycodestyle.pycqa.org/en/latest/intro.html#error-codes)
rule (E502) from pycodestyle.

## Test Plan

New fixture has been added

Part of #2402
2024-03-11 21:15:06 -04:00
Mathieu Kniewallner fc7139d9a5
[`flake8-bandit`]: Implement `S610` rule (#10316)
Part of https://github.com/astral-sh/ruff/issues/1646.

## Summary

Implement `S610` rule from `flake8-bandit`. 

Upstream references:
- Implementation:
https://github.com/PyCQA/bandit/blob/1.7.8/bandit/plugins/django_sql_injection.py#L20-L97
- Test cases:
https://github.com/PyCQA/bandit/blob/1.7.8/examples/django_sql_injection_extra.py
- Test assertion:
https://github.com/PyCQA/bandit/blob/1.7.8/tests/functional/test_functional.py#L517-L524

The implementation in `bandit` targets additional arguments (`params`,
`order_by` and `select_params`) but doesn't seem to do anything with
them in the end, so I did not include them in the implementation.

Note that this rule could be prone to false positives, as ideally we
would want to check if `extra()` is tied to a [Django
queryset](https://docs.djangoproject.com/en/5.0/ref/models/querysets/),
but AFAIK Ruff is not able to resolve classes outside of the current
module.

## Test Plan

Snapshot tests
2024-03-11 20:22:02 -04:00
Charlie Marsh f8f56186b3
[`pylint`] Avoid false-positive slot non-assignment for `__dict__` (`PLE0237`) (#10348)
Closes https://github.com/astral-sh/ruff/issues/10306.
2024-03-11 18:48:56 -04:00
Charlie Marsh 02fc521369
Wrap expressions in parentheses when negating (#10346)
## Summary

When negating an expression like `a or b`, we need to wrap it in
parentheses, e.g., `not (a or b)` instead of `not a or b`, due to
operator precedence.

Closes https://github.com/astral-sh/ruff/issues/10335.

## Test Plan

`cargo test`
2024-03-11 18:20:55 -04:00
Alex Waygood 4b0666919b
F821, F822: fix false positive for `.pyi` files; add more test coverage for `.pyi` files (#10341)
This PR fixes the following false positive in a `.pyi` stub file:

```py
x: int
y = x  # F821 currently emitted here, but shouldn't be in a stub file
```

In a `.py` file, this is invalid regardless of whether `from __future__ import annotations` is enabled or not. In a `.pyi` stub file, however, it's always valid, as an annotation counts as a binding in a stub file even if no value is assigned to the variable.

I also added more test coverage for `.pyi` stub files in various edge cases where ruff's behaviour is currently correct, but where `.pyi` stub files do slightly different things to `.py` files.
2024-03-11 22:15:24 +00:00
Hoël Bagard 8d73866f70
[`pycodestyle`] Do not trigger `E225` and `E275` when the next token is a ')' (#10315)
## Summary

Fixes #10295.

`E225` (`Missing whitespace around operator`) and `E275` (`Missing
whitespace after keyword`) try to add a white space even when the next
character is a `)` (which is a syntax error in most cases, the
exceptions already being handled). This causes `E202` (`Whitespace
before close bracket`) to try to remove the added whitespace, resulting
in an infinite loop when `E225`/`E275` re-add it.
This PR adds an exception in `E225` and `E275` to not trigger in case
the next token is a `)`. It is a bit simplistic, but it solves the
example given in the issue without introducing a change in behavior
(according to the fixtures).

## Test Plan

`cargo test` and the `ruff-ecosystem` check were used to check that the
PR's changes do not have side-effects.
A new fixture was added to check that running the 3 rules on the example
given in the issue does not cause ruff to fail to converge.
2024-03-11 21:23:18 +00:00
Mathieu Kniewallner bc693ea13a
[`flake8-bandit`] Implement upstream updates for `S311`, `S324` and `S605` (#10313)
## Summary

Pick up updates made in latest
[releases](https://github.com/PyCQA/bandit/releases) of `bandit`:
- `S311`: https://github.com/PyCQA/bandit/pull/940 and
https://github.com/PyCQA/bandit/pull/1096
- `S324`: https://github.com/PyCQA/bandit/pull/1018
- `S605`: https://github.com/PyCQA/bandit/pull/1116

## Test Plan

Snapshot tests
2024-03-11 21:07:58 +00:00
Jane Lewis 0c84fbb6db
`ruff server` - A new built-in LSP for Ruff, written in Rust (#10158)
<!--
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 introduces the `ruff_server` crate and a new `ruff server`
command. `ruff_server` is a re-implementation of
[`ruff-lsp`](https://github.com/astral-sh/ruff-lsp), written entirely in
Rust. It brings significant performance improvements, much tighter
integration with Ruff, a foundation for supporting entirely new language
server features, and more!

This PR is an early version of `ruff_lsp` that we're calling the
**pre-release** version. Anyone is more than welcome to use it and
submit bug reports for any issues they encounter - we'll have some
documentation on how to set it up with a few common editors, and we'll
also provide a pre-release VSCode extension for those interested.

This pre-release version supports:
- **Diagnostics for `.py` files**
- **Quick fixes**
- **Full-file formatting**
- **Range formatting**
- **Multiple workspace folders**
- **Automatic linter/formatter configuration** - taken from any
`pyproject.toml` files in the workspace.

Many thanks to @MichaReiser for his [proof-of-concept
work](https://github.com/astral-sh/ruff/pull/7262), which was important
groundwork for making this PR possible.

## Architectural Decisions

I've made an executive choice to go with `lsp-server` as a base
framework for the LSP, in favor of `tower-lsp`. There were several
reasons for this:

1. I would like to avoid `async` in our implementation. LSPs are mostly
computationally bound rather than I/O bound, and `async` adds a lot of
complexity to the API, while also making harder to reason about
execution order. This leads into the second reason, which is...
2. Any handlers that mutate state should be blocking and run in the
event loop, and the state should be lock-free. This is the approach that
`rust-analyzer` uses (also with the `lsp-server`/`lsp-types` crates as a
framework), and it gives us assurances about data mutation and execution
order. `tower-lsp` doesn't support this, which has caused some
[issues](https://github.com/ebkalderon/tower-lsp/issues/284) around data
races and out-of-order handler execution.
3. In general, I think it makes sense to have tight control over
scheduling and the specifics of our implementation, in exchange for a
slightly higher up-front cost of writing it ourselves. We'll be able to
fine-tune it to our needs and support future LSP features without
depending on an upstream maintainer.

## Test Plan

The pre-release of `ruff_server` will have snapshot tests for common
document editing scenarios. An expanded test suite is on the roadmap for
future version of `ruff_server`.
2024-03-08 20:57:23 -08:00
Charlie Marsh a892fc755d
Bump version to v0.3.2 (#10304) 2024-03-09 00:24:22 +00:00
Gautier Moin a067d87ccc
Fix incorrect `Parameter` range for `*args` and `**kwargs` (#10283)
## Summary

Fix #10282 

This PR updates the Python grammar to include the `*` character in
`*args` `**kwargs` in the range of the `Parameter`
```
def f(*args, **kwargs): pass
#      ~~~~    ~~~~~~    <-- range before the PR
#     ^^^^^  ^^^^^^^^    <-- range after
```

The invalid syntax `def f(*, **kwargs): ...` is also now correctly
reported.

## Test Plan

Test cases were added to `function.rs`.
2024-03-08 18:57:49 -05:00
Micha Reiser b64f2ea401
Formatter: Improve single-with item formatting for Python 3.8 or older (#10276)
## Summary

This PR changes how we format `with` statements with a single with item
for Python 3.8 or older. This change is not compatible with Black.

This is how we format a single-item with statement today 

```python
def run(data_path, model_uri):
    with pyspark.sql.SparkSession.builder.config(
        key="spark.python.worker.reuse", value=True
    ).config(key="spark.ui.enabled", value=False).master(
        "local-cluster[2, 1, 1024]"
    ).getOrCreate():
        # ignore spark log output
        spark.sparkContext.setLogLevel("OFF")
        print(score_model(spark, data_path, model_uri))
```

This is different than how we would format the same expression if it is
inside any other clause header (`while`, `if`, ...):

```python
def run(data_path, model_uri):
    while (
        pyspark.sql.SparkSession.builder.config(
            key="spark.python.worker.reuse", value=True
        )
        .config(key="spark.ui.enabled", value=False)
        .master("local-cluster[2, 1, 1024]")
        .getOrCreate()
    ):
        # ignore spark log output
        spark.sparkContext.setLogLevel("OFF")
        print(score_model(spark, data_path, model_uri))

```

Which seems inconsistent to me. 

This PR changes the formatting of the single-item with Python 3.8 or
older to match that of other clause headers.

```python
def run(data_path, model_uri):
    with (
        pyspark.sql.SparkSession.builder.config(
            key="spark.python.worker.reuse", value=True
        )
        .config(key="spark.ui.enabled", value=False)
        .master("local-cluster[2, 1, 1024]")
        .getOrCreate()
    ):
        # ignore spark log output
        spark.sparkContext.setLogLevel("OFF")
        print(score_model(spark, data_path, model_uri))
```

According to our versioning policy, this style change is gated behind a
preview flag.

## Test Plan

See added tests.

Added
2024-03-08 23:56:02 +00:00
Micha Reiser 4bce801065
Fix unstable with-items formatting (#10274)
## Summary

Fixes https://github.com/astral-sh/ruff/issues/10267

The issue with the current formatting is that the formatter flips
between the `SingleParenthesizedContextManager` and
`ParenthesizeIfExpands` or `SingleWithTarget` because the layouts use
incompatible formatting ( `SingleParenthesizedContextManager`:
`maybe_parenthesize_expression(context)` vs `ParenthesizeIfExpands`:
`parenthesize_if_expands(item)`, `SingleWithTarget`:
`optional_parentheses(item)`.

The fix is to ensure that the layouts between which the formatter flips
when adding or removing parentheses are the same. I do this by
introducing a new `SingleWithoutTarget` layout that uses the same
formatting as `SingleParenthesizedContextManager` if it has no target
and prefer `SingleWithoutTarget` over using `ParenthesizeIfExpands` or
`SingleWithTarget`.

## Formatting change

The downside is that we now use `maybe_parenthesize_expression` over
`parenthesize_if_expands` for expressions where
`can_omit_optional_parentheses` returns `false`. This can lead to stable
formatting changes. I only found one formatting change in our ecosystem
check and, unfortunately, this is necessary to fix the instability (and
instability fixes are okay to have as part of minor changes according to
our versioning policy)

The benefit of the change is that `with` items with a single context
manager and without a target are now formatted identically to how the
same expression would be formatted in other clause headers.

## Test Plan

I ran the ecosystem check locally
2024-03-08 23:48:47 +00:00
Micha Reiser a56d42f183
Refactor with statement formatting to have explicit layouts (#10296)
## Summary

This PR refactors the with item formatting to use more explicit layouts
to make it easier to understand the different formatting cases.

The benefit of the explicit layout is that it makes it easier to reasons
about layout transition between format runs. For example, today it's
possible that `SingleWithTarget` or `ParenthesizeIfExpands` add
parentheses around the with items for `with aaaaaaaaaa + bbbbbbbbbbbb:
pass`, resulting in `with (aaaaaaaaaa + bbbbbbbbbbbb): pass`. The
problem with this is that the next formatting pass uses the
`SingleParenthesizedContextExpression` layout that uses
`maybe_parenthesize_expression` which is different from
`parenthesize_if_expands(&expr)` or `optional_parentheses(&expr)`.

## Test Plan

`cargo test`

I ran the ecosystem checks locally and there are no changes.
2024-03-08 18:40:39 -05:00
Alex Waygood 1d97f27335
Start tracking quoting style in the AST (#10298)
This PR modifies our AST so that nodes for string literals, bytes literals and f-strings all retain the following information:
- The quoting style used (double or single quotes)
- Whether the string is triple-quoted or not
- Whether the string is raw or not

This PR is a followup to #10256. Like with that PR, this PR does not, in itself, fix any bugs. However, it means that we will have the necessary information to preserve quoting style and rawness of strings in the `ExprGenerator` in a followup PR, which will allow us to provide a fix for https://github.com/astral-sh/ruff/issues/7799.

The information is recorded on the AST nodes using a bitflag field on each node, similarly to how we recorded the information on `Tok::String`, `Tok::FStringStart` and `Tok::FStringMiddle` tokens in #10298. Rather than reusing the bitflag I used for the tokens, however, I decided to create a custom bitflag for each AST node.

Using different bitflags for each node allows us to make invalid states unrepresentable: it is valid to set a `u` prefix on a string literal, but not on a bytes literal or an f-string. It also allows us to have better debug representations for each AST node modified in this PR.
2024-03-08 19:11:47 +00:00
Micha Reiser 965adbed4b
Fix trailing kwargs end of line comment after slash (#10297)
## Summary

Fixes the handling end of line comments that belong to `**kwargs` when
the `**kwargs` come after a slash.

The issue was that we missed to include the `**kwargs` start position
when determining the start of the next node coming after the `/`.

Fixes https://github.com/astral-sh/ruff/issues/10281

## Test Plan

Added test
2024-03-08 14:45:26 +00:00
Alex Waygood c504d7ab11
Track quoting style in the tokenizer (#10256) 2024-03-08 08:40:06 +00:00
Tom Kuson 72c9f7e4c9
Include actual conditions in E712 diagnostics (#10254)
## Summary

Changes the generic recommendation to replace

```python
if foo == True: ...
```

with `if cond:` to `if foo:`.

Still uses a generic message for compound comparisons as a specific
message starts to become confusing. For example,

```python
if foo == True != False: ...
```

produces two recommendations, one of which would recommend `if True:`,
which is confusing.

Resolves [recommendation in a previous
PR](https://github.com/astral-sh/ruff/pull/8613/files#r1514915070).

## Test Plan

`cargo nextest run`
2024-03-08 01:20:56 +00:00
Charlie Marsh 57be3fce90
Treat `typing.Annotated` subscripts as type definitions (#10285)
## Summary

I think this code has existed since the start of `typing.Annotated`
support (https://github.com/astral-sh/ruff/pull/333), and was then
overlooked over a series of refactors.

Closes https://github.com/astral-sh/ruff/issues/10279.
2024-03-07 19:51:54 -05:00