Commit Graph

1010 Commits

Author SHA1 Message Date
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
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
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
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
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 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
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
Charlie Marsh 4436dec1d9
Fix broken comment in `too-many-branches` (#11440) 2024-05-16 02:25:20 +00: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
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
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
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
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
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
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
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
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
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
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
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
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
Tushar Sadhwani bc3f4fa3bc
[`flake8-pyi`] Implement `PYI059` (`generic-not-last-base-class`) (#11233) 2024-05-07 10:07:56 +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 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 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
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 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
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
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 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
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
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
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
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
Alex Waygood 21d824abfd
[`pylint`] Also emit `PLR0206` for properties with variadic parameters (#11200) 2024-04-30 11:59:37 +01:00
Micha Reiser 5561d445d7
linter: Enable test-rules for test build (#11201) 2024-04-30 08:06:47 +02: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
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
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
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
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
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
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
Alex Waygood 37af6e6147
[`flake8-pyi`] Allow simple assignments to `None` in enum class scopes (`PYI026`) (#11128) 2024-04-24 15:13:55 +01: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
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
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