Commit Graph

351 Commits

Author SHA1 Message Date
Seo Sanghyeon df7fb95cbc
Index multiline f-strings (#9837)
Fix #9777.
2024-02-05 21:25:33 -05:00
Charlie Marsh 041ce1e166
Respect generic `Protocol` in ellipsis removal (#9841)
Closes https://github.com/astral-sh/ruff/issues/9840.
2024-02-05 19:36:16 +00:00
Zanie Blue 84aea7f0c8
Drop `__get__` and `__set__` from `unnecessary-dunder-call` (#9791)
These are for descriptors which affects the behavior of the object _as a
property_; I do not think they should be called directly but there is no
alternative when working with the object directly.

Closes https://github.com/astral-sh/ruff/issues/9789
2024-02-05 10:54:29 -05:00
Charlie Marsh 602f8b8250
Remove CST-based fixer for `C408` (#9822)
## Summary

We have to keep the fixer for a specific case: `dict` calls that include
keyword-argument members.
2024-02-04 22:26:51 -05:00
Charlie Marsh a6bc4b2e48
Remove CST-based fixers for `C405` and `C409` (#9821) 2024-02-05 02:17:34 +00:00
Charlie Marsh c5fa0ccffb
Remove CST-based fixers for `C400`, `C401`, `C410`, and `C418` (#9819) 2024-02-04 21:00:11 -05:00
Charlie Marsh dd77d29d0e
Remove LibCST-based fixer for `C403` (#9818)
## Summary

Experimenting with rewriting one of the comprehension fixes _without_
LibCST.
2024-02-04 20:08:19 -05:00
Jane Lewis e0a6034cbb
Implement RUF027: `Missing F-String Syntax` lint (#9728)
<!--
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

Fixes #8151

This PR implements a new rule, `RUF027`.

## What it does
Checks for strings that contain f-string syntax but are not f-strings.

### Why is this bad?
An f-string missing an `f` at the beginning won't format anything, and
instead treat the interpolation syntax as literal.

### Example

```python
name = "Sarah"
dayofweek = "Tuesday"
msg = "Hello {name}! It is {dayofweek} today!"
```

It should instead be:
```python
name = "Sarah"
dayofweek = "Tuesday"
msg = f"Hello {name}! It is {dayofweek} today!"
```

## Heuristics
Since there are many possible string literals which contain syntax
similar to f-strings yet are not intended to be,
this lint will disqualify any literal that satisfies any of the
following conditions:
1. The string literal is a standalone expression. For example, a
docstring.
2. The literal is part of a function call with keyword arguments that
match at least one variable (for example: `format("Message: {value}",
value = "Hello World")`)
3. The literal (or a parent expression of the literal) has a direct
method call on it (for example: `"{value}".format(...)`)
4. The string has no `{...}` expression sections, or uses invalid
f-string syntax.
5. The string references variables that are not in scope, or it doesn't
capture variables at all.
6. Any format specifiers in the potential f-string are invalid.

## Test Plan

I created a new test file, `RUF027.py`, which is both an example of what
the lint should catch and a way to test edge cases that may trigger
false positives.
2024-02-03 00:21:03 +00:00
Charlie Marsh ee5b07d4ca
Skip empty lines when determining base indentation (#9795)
## Summary

It turns out we saw a panic in cases when dedenting blocks like the `def
wrapper` here:

```python
def instrument_url(f: UrlFuncT) -> UrlFuncT:
    # TODO: Type this with ParamSpec to preserve the function signature.
    if not INSTRUMENTING:  # nocoverage -- option is always enabled; should we remove?
        return f
    else:

        def wrapper(
            self: "ZulipTestCase", url: str, info: object = {}, **kwargs: Union[bool, str]
        ) -> HttpResponseBase:
```

Since we relied on the first line to determine the indentation, instead
of the first non-empty line.

## Test Plan

`cargo test`
2024-02-02 19:42:47 +00:00
Charlie Marsh c3ca34543f
Skip LibCST parsing for standard dedent adjustments (#9769)
## Summary

Often, when fixing, we need to dedent a block of code (e.g., if we
remove an `if` and dedent its body). Today, we use LibCST to parse and
adjust the indentation, which is really expensive -- but this is only
really necessary if the block contains a multiline string, since naively
adjusting the indentation for such a string can change the whitespace
_within_ the string.

This PR uses a simple dedent implementation for cases in which the block
doesn't intersect with a multi-line string (or an f-string, since we
don't support tracking multi-line strings for f-strings right now).

We could improve this even further by using the ranges to guide the
dedent function, such that we don't apply the dedent if the line starts
within a multiline string. But that would also need to take f-strings
into account, which is a little tricky.

## Test Plan

`cargo test`
2024-02-02 18:13:46 +00:00
Zanie Blue 994514d686 Redirect `PHG001` to `S307` and `PGH002` to `G010` (#9756)
Follow-up to #9754 and #9689. Alternative to #9714.
Replaces #7506 and #7507
Same ideas as #9755
Part of #8931
2024-02-01 13:35:02 -06:00
Zanie Blue a578414246 Redirect `TRY200` to `B904` (#9755)
Follow-up to #9754 and #9689. Alternative to #9714.

Marks `TRY200` as removed and redirects to `B904` instead of marking as
deprecated and suggesting `B904` instead.
2024-02-01 13:35:02 -06:00
Charlie Marsh 85a7edcc70 Recategorize `runtime-string-union` to `TCH010` (#9721)
## Summary

This rule was added to `flake8-type-checking` as `TC010`. We're about to
stabilize it, so we might as well use the correct code.

See: https://github.com/astral-sh/ruff/issues/9573.
2024-02-01 13:35:02 -06:00
Zanie Blue e0bc08a758 Add rule removal infrastructure (#9691)
Similar to https://github.com/astral-sh/ruff/pull/9689 — retains removed
rules for better error messages and documentation but removed rules
_cannot_ be used in any context.

Removes PLR1706 as a useful test case and something we want to
accomplish in #9680 anyway. The rule was in preview so we do not need to
deprecate it first.

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

## Test plan

<img width="1110" alt="Rules table"
src="https://github.com/astral-sh/ruff/assets/2586601/ac9fa682-623c-44aa-8e51-d8ab0d308355">

<img width="1110" alt="Rule page"
src="https://github.com/astral-sh/ruff/assets/2586601/05850b2d-7ca5-49bb-8df8-bb931bab25cd">
2024-02-01 13:35:02 -06:00
Zanie 7962bca40a Recategorize `static-key-dict-comprehension` from `RUF011` to `B035` (#9428)
## Summary

This rule was added to flake8-bugbear. In general, we tend to prefer
redirecting to prominent plugins when our own rules are reimplemented
(since more projects have `B` activated than `RUF`).

## Test Plan

`cargo test`
# Conflicts:
#	crates/ruff_linter/src/rules/ruff/rules/mod.rs
2024-02-01 13:35:02 -06:00
Aleksei Latyshev 2cc8acb0b7
[`refurb`] Implement `metaclass_abcmeta` (`FURB180`) (#9658)
## Summary

Implement [use-abc-shorthand
(FURB180)](https://github.com/dosisod/refurb/blob/master/refurb/checks/readability/use_abc_shorthand.py)
lint.

I changed the name to be more conformant with ruff rule-naming rules.


## Test Plan

cargo test
2024-01-31 22:31:12 +00:00
Charlie Marsh ad83944ded
Detect multi-statement lines in else removal (#9748)
The condition here wasn't quite right -- we can have multiple
statements, all on the same line.

Closes https://github.com/astral-sh/ruff/issues/9732.
2024-01-31 22:08:32 +00:00
Seo Sanghyeon 6e225cb57c
Removing trailing whitespace inside multiline strings is unsafe (#9744)
Fix #8037.
2024-01-31 21:45:23 +00:00
Christopher Covington 7ae7bf6e30
Support `IfExp` with dual string arms in `invalid-envvar-default` (#9734)
## Summary

Just like #6537 and #6538 but for the `default` second parameter to
`getenv()`.

Also rename "BAD" to "BAR" in the tests, since those strings shouldn't
trigger the rule.

## Test Plan

Added passing and failing examples to `invalid_envvar_default.py`.
2024-01-31 10:41:24 -05:00
Alex Waygood 6bb126415d
RUF023: Don't sort `__match_args__`, only `__slots__` (#9724)
Fixes #9723. I'm pretty embarrassed I forgot that order was important
here :(
2024-01-30 22:44:49 +00:00
Mikko Leppänen 79f0522eb7
[`flake8-async`] Take `pathlib.Path` into account when analyzing async functions (#9703)
## Summary

This review contains a fix for
[ASYNC101](https://docs.astral.sh/ruff/rules/open-sleep-or-subprocess-in-async-function/)
(open-sleep-or-subprocess-in-async-function)

The problem is that ruff does not take open calls from pathlib.Path into
account in async functions. Path.open() call is still a blocking call.
In addition, PTH123 suggests to use pathlib.Path instead of os.open. So
this might create an additional confusion.

See: https://github.com/astral-sh/ruff/issues/6892

## Test Plan

```bash
cargo test
```
2024-01-30 17:42:50 +00:00
Alex Waygood 0c8d140321
RUF022, RUF023: never add two trailing commas to the end of a sequence (#9698)
Fixes the issues highlighted in
https://github.com/astral-sh/ruff/issues/8402#issuecomment-1916203707
and
https://github.com/astral-sh/ruff/issues/8402#issuecomment-1916213693
2024-01-30 17:19:38 +00:00
Steve C f0e598ea84
[`flake8-return`] Fix indentation syntax error (`RET505`) (#9705)
## Summary

Fix for
https://github.com/astral-sh/ruff/issues/8402#issuecomment-1916223126

## Test Plan

`cargo test`
2024-01-30 16:46:04 +00:00
Bartosz Sławecki b6a96452fc
[`pylint`] Add `__mro_entries__` to known dunder methods (`PLW3201`) (#9706)
## Summary

This change adds
[`__mro_entries__`](https://docs.python.org/3/reference/datamodel.html#object.__mro_entries__)
to the list of known dunder methods.
2024-01-30 11:41:19 -05:00
Steve C 214563261d
[`flake8-simplify`] - Fix syntax error in autofix (`SIM114`) (#9704)
## Summary

A fix for
https://github.com/astral-sh/ruff/issues/8402#issuecomment-1916215124

Improves the code, as well. :)

## Test Plan

`cargo test`
2024-01-30 11:36:44 -05:00
Steve C dacda0f202
[`pylint`] Show verbatim constant in `magic-value-comparison` (`PLR2004`) (#9694)
## Summary

Tweaks PLR2004 to show the literal source text, rather than the constant
value.

I noticed this when I had a hexadecimal constant, and the linter turned
it into base-10.

Now, if you have `0x300`, it will show `0x300` instead of `768`.

Also, added backticks around the constant in the output message.

## Test Plan

`cargo test`
2024-01-30 00:22:09 -05:00
Charlie Marsh 11449acfd9
Avoid marking `InitVar` as a typing-only annotation (#9688)
## Summary

Given:

```python
from dataclasses import InitVar, dataclass

@dataclass
class C:
    i: int
    j: int = None
    database: InitVar[DatabaseType] = None

    def __post_init__(self, database):
        if self.j is None and database is not None:
            self.j = database.lookup('j')

c = C(10, database=my_database)
```

We should avoid marking `InitVar` as typing-only, since it _is_ required
by the dataclass at runtime.

Note that by default, we _already_ don't flag this, since the
`@dataclass` member is needed at runtime too -- so it's only a problem
with `strict` mode.

Closes https://github.com/astral-sh/ruff/issues/9666.
2024-01-29 16:27:20 -05:00
Charlie Marsh a6f7100b55
[`pycodestyle`] Allow `dtype` comparisons in `type-comparison` (#9676)
## Summary

Per https://github.com/astral-sh/ruff/issues/9570:

> `dtype` are a bit of a strange beast, but definitely best thought of
as instances, not classes, and they are meant to be comparable not just
to their own class, but also to the corresponding scalar types (e.g.,
`x.dtype == np.float32`) and strings (e.g., `x.dtype == ['i1,i4']`;
basically, `__eq__` always tries to do `dtype(other)`.

This PR thus allows comparisons to `dtype` in preview.

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

## Test Plan

`cargo test`
2024-01-29 12:39:01 -05:00
Mikko Leppänen ad2cfa3dba
[flake8-return] Consider exception suppress for unnecessary assignment (#9673)
## Summary

This review contains a fix for
[RET504](https://docs.astral.sh/ruff/rules/unnecessary-assign/)
(unnecessary-assign)

The problem is that Ruff suggests combining a return statement inside
contextlib.suppress. Even though it is an unsafe fix it might lead to an
invalid code that is not equivalent to the original one.

See: https://github.com/astral-sh/ruff/issues/5909

## Test Plan

```bash
cargo test
```
2024-01-29 12:29:05 -05:00
Mikko Leppänen b9139a31d5
[`flake8-pie`] Omit bound tuples passed to `.startswith` or `.endswith` (#9661)
## Summary

This review contains a fix for
[PIE810](https://docs.astral.sh/ruff/rules/multiple-starts-ends-with/)
(multiple-starts-ends-with)

The problem is that ruff suggests combining multiple startswith/endswith
calls into a single call even though there might be a call with tuple of
strs. This leads to calling startswith/endswith with tuple of tuple of
strs which is incorrect and violates startswith/endswith conctract and
results in runtime failure.

However the following will be valid and fixed correctly => 
```python
x = ("hello", "world")
y = "h"
z = "w"
msg = "hello world"

if msg.startswith(x) or msg.startswith(y) or msg.startswith(z) :
      sys.exit(1)
```
```
ruff --fix --select PIE810 --unsafe-fixes
```
=> 
```python
if msg.startswith(x) or msg.startswith((y,z)):
      sys.exit(1)
```

See: https://github.com/astral-sh/ruff/issues/8906

## Test Plan

```bash
cargo test
```
2024-01-28 19:29:04 +00:00
Charlie Marsh 7329bf459c
Avoid panic when fixing inlined else blocks (#9657)
Closes https://github.com/astral-sh/ruff/issues/9655.
2024-01-27 14:15:33 +00:00
Charlie Marsh 157d5bacfc
[`pydocstyle`] Re-implement `last-line-after-section` (`D413`) (#9654)
## Summary

This rule was just incorrect, it didn't match the examples in the docs.
(It's a very rarely-used rule since it's not included in any of the
conventions.)

Closes https://github.com/astral-sh/ruff/issues/9452.
2024-01-26 19:30:59 +00:00
Mikko Leppänen d496c164d3
[`ruff`] Guard against use of `default_factory` as a keyword argument (`RUF026`) (#9651)
## Summary

Add a rule for defaultdict(default_factory=callable). Instead suggest
using defaultdict(callable).

See: https://github.com/astral-sh/ruff/issues/9509

If a user tries to bind a "non-callable" to default_factory, the rule
ignores it. Another option would be to warn that it's probably not what
you want. Because Python allows the following:

```python 
from collections import defaultdict

defaultdict(default_factory=1)
```
this raises after you actually try to use it:

```python
dd = defaultdict(default_factory=1)
dd[1]
```
=> 
```bash
KeyError: 1
```

Instead using callable directly in the constructor it will raise (not
being a callable):

```python 
from collections import defaultdict

defaultdict(1)
```
=> 
```bash
TypeError: first argument must be callable or None
```




## Test Plan

```bash
cargo test
```
2024-01-26 19:10:05 +00:00
Charlie Marsh b61b0edeea
Add Pydantic's `BaseConfig` to default-copy list (#9650)
Closes https://github.com/astral-sh/ruff/issues/9647.
2024-01-26 14:54:48 +00:00
Steve C ffd13e65ae
[`flake8-return`] - Add fixes for (`RET505`, `RET506`, `RET507`, `RET508`) (#9595) 2024-01-25 08:28:32 +01:00
Steve C dba2cb79cb
[`pylint`] Implement `too-many-nested-blocks` (`PLR1702`) (#9172)
## Summary

Implement
[`PLR1702`/`too-many-nested-blocks`](https://pylint.readthedocs.io/en/latest/user_guide/messages/refactor/too-many-nested-blocks.html)

See: #970 

## Test Plan

`cargo test`
2024-01-24 19:30:01 +00:00
Mikko Leppänen 45628a5883
[`flake8-return`] Take `NoReturn` annotation into account when analyzing implicit returns (#9636)
## Summary

When we are analyzing the implicit return rule this change add an
additional check to verify if the call expression has been annotated
with NoReturn type from typing module.

See: https://github.com/astral-sh/ruff/issues/5474

## Test Plan

```bash
cargo test
```
2024-01-24 17:19:26 +00:00
Akira Noda 57313d9d63
[`pylint`] Implement `assigning-non-slot` (`E0237`) (#9623)
## Summary

Implement [assigning-non-slot /
E0237](https://pylint.readthedocs.io/en/latest/user_guide/messages/error/assigning-non-slot.html)

related #970

## Test Plan

`cargo test`
2024-01-24 02:50:22 +00:00
Mikko Leppänen eab1a6862b
[`ruff`] Detect unnecessary `dict` comprehensions for iterables (`RUF025`) (#9613)
## Summary

Checks for unnecessary `dict` comprehension when creating a new
dictionary from iterable. Suggest to replace with
`dict.fromkeys(iterable)`

See: https://github.com/astral-sh/ruff/issues/9592

## Test Plan

```bash
cargo test
```
2024-01-24 02:15:38 +00:00
Alex Waygood f5061dbb8e
Add a rule/autofix to sort `__slots__` and `__match_args__` (#9564)
## Summary

This PR introduces a new rule to sort `__slots__` and `__match_args__`
according to a [natural sort](https://en.wikipedia.org/wiki/Natural_sort_order), as was
requested in https://github.com/astral-sh/ruff/issues/1198#issuecomment-1881418365.

The implementation here generalises some of the machinery introduced in
3aae16f1bd
so that different kinds of sorts can be applied to lists of string
literals. (We use an "isort-style" sort for `__all__`, but that isn't
really appropriate for `__slots__` and `__match_args__`, where nearly
all items will be snake_case.) Several sections of code have been moved
from `sort_dunder_all.rs` to a new module, `sorting_helpers.rs`, which
`sort_dunder_all.rs` and `sort_dunder_slots.rs` both make use of.

`__match_args__` is very similar to `__all__`, in that it can only be a
tuple or a list. `__slots__` differs from the other two, however, in
that it can be any iterable of strings. If slots is a dictionary, the
values are used by the builtin `help()` function as per-attribute
docstrings that show up in the output of `help()`. (There's no
particular use-case for making `__slots__` a set, but it's perfectly
legal at runtime, so there's no reason for us not to handle it in this
rule.)

Note that we don't do an autofix for multiline `__slots__` if `__slots__` is a dictionary: that's out of scope. Everything else, we can nearly always fix, however.

## Test Plan

`cargo test` / `cargo insta review`.

I also ran this rule on CPython, and the diff looked pretty good

---

Co-authored-by: Micha Reiser <micha@reiser.io>
2024-01-22 12:21:55 +00:00
Steve C 9c8a4d927e
[`flake8-simplify`] Add fix for `if-with-same-arms` (`SIM114`) (#9591)
## Summary

 add fix for `if-with-same-arms` / `SIM114`

Also preserves comments!

## Test Plan

`cargo test`
2024-01-22 04:37:18 +00:00
Steve C e54ed28ba9
[`pylint`] Add fix for `collapsible-else-if` (`PLR5501`) (#9594)
## Summary

adds a fix for `collapsible-else-if` / `PLR5501`

## Test Plan

`cargo test`
2024-01-21 19:53:15 -05:00
Tom Kuson 1e4b421a00
[`ruff`] Implement `mutable-fromkeys-value` (`RUF024`) (#9597)
## Summary

Implement rule `mutable-fromkeys-value` (`RUF023`).

Autofixes

```python
dict.fromkeys(foo, [])
```

to

```python
{key: [] for key in foo}
```

The fix is marked as unsafe as it changes runtime behaviour. It also
uses `key` as the comprehension variable, which may not always be
desired.

Closes #4613.

## Test Plan

`cargo test`
2024-01-22 00:22:02 +00:00
Steve C 837984168a
[`pycodestyle`] Add fix for `multiple-imports-on-one-line` (`E401`) (#9518)
## Summary

Add autofix for `multiple_imports_on_one_line`, `E401`

## Test Plan

`cargo test`
2024-01-21 15:33:38 -05:00
Steve C 9e5f3f1b1b
[`pylint`] Add fix for `useless-else-on-loop` (`PLW0120`) (#9590)
## Summary

adds fix for `useless-else-on-loop` / `PLW0120`.

## Test Plan

`cargo test`
2024-01-21 11:17:58 -05:00
Steve C 49a445a23d
[`pylint`] Implement `potential-index-error` (`PLE0643`) (#9545)
## Summary

add `potential-index-error` rule (`PLE0643`)

See: #970 

## Test Plan

`cargo test`
2024-01-21 03:59:48 +00:00
Alex Waygood b3a6f0ce81
[flake8-pyi] Fix PYI049 false negatives on call-based TypedDicts (#9567)
## Summary

Fixes another of the bullet points from #8771

## Test Plan

`cargo test` / `cargo insta review`
2024-01-18 10:01:21 +00:00
Thomas M Kehrenberg 7be706641d
[`pylint`] Exclude `self` and `cls` when counting method arguments (#9563)
## Summary

This PR detects whether PLR0917 is being applied to a method or class
method, and if so, it ignores the first argument for the purposes of
counting the number of positional arguments.

## Test Plan

New tests have been added to the corresponding fixture.

Closes #9552.
2024-01-18 03:17:45 +00:00
Alex Waygood 848e473f69
[flake8-pyi] Fix PYI047 false negatives on PEP-695 type aliases (#9566)
## Summary

Fixes one of the issues listed in
https://github.com/astral-sh/ruff/issues/8771. Fairly straightforward!

## Test Plan

`cargo test` / `cargo insta review`
2024-01-17 22:14:18 -05:00
Charlie Marsh 8118d29419
Rename `ruff_cli` crate to `ruff` (#9557)
## Summary

Long ago, we had a single `ruff` crate. We started to break that up, and
at some point, we wanted to separate the CLI from the core library. So
we created `ruff_cli`, which created a `ruff` binary. Later, the `ruff`
crate was renamed to `ruff_linter` and further broken up into additional
crates.

(This is all from memory -- I didn't bother to look through the history
to ensure that this is 100% correct :))

Now that `ruff` no longer exists, this PR renames `ruff_cli` to `ruff`.
The primary benefit is that the binary target and the crate name are now
the same, which helps with downstream tooling like `cargo-dist`, and
also removes some complexity from the crate and `Cargo.toml` itself.

## Test Plan

- Ran `rm -rf target/release`.
- Ran `cargo build --release`.
- Verified that `./target/release/ruff` was created.
2024-01-16 17:47:01 -05:00