Commit Graph

1634 Commits

Author SHA1 Message Date
Charlie Marsh 603d3e1984 Add quoted annotation rules 2023-07-14 16:16:21 -04:00
Charlie Marsh 402b3c7f04 Expand scope of quoted-annotation rule 2023-07-14 16:15:38 -04:00
Charlie Marsh 81b88dcfb9
Misc. minor refactors to `incorrect-dict-iterator` (#5762)
## Summary

Mostly a no-op: use a single match for key-value, use identifier range
rather than re-lexing, respect our `dummy-variable-rgx` setting.
2023-07-14 17:29:25 +00:00
Micha Reiser 8187bf9f7e
Cover Black's `is_aritmetic_like` formatting (#5738) 2023-07-14 17:54:58 +02:00
Charlie Marsh 513de13c46
Remove `B904`'s lowercase exemption (#5751)
## Summary

It looks like bugbear, [from the
start](https://github.com/PyCQA/flake8-bugbear/pull/181#issuecomment-904314876),
has had an exemption here to exempt `raise lower_case_var`. I looked at
Hypothesis and Trio, which are mentioned in that issue, and Hypothesis
has exactly one case of this, and Trio has none, so IMO it doesn't seem
worth special-casing.

Closes https://github.com/astral-sh/ruff/issues/5664.
2023-07-14 11:46:21 -04:00
Justin Prieto 816f7644a9
Fix nested calls to `sorted` with differing arguments (#5761)
## Summary

Nested calls to `sorted` can only be collapsed if the calls are
identical (i.e., they have the exact same keyword arguments).
Update C414 to only flag such cases.

Fixes #5712

## Test Plan

Updated snapshots.
Tested against flake8-comprehensions. It incorrectly flags these cases.
2023-07-14 13:43:47 +00:00
konsti fb46579d30
Add Regression test for #5605, where formatting `x[:,]` failed. (#5759)
#5605 has been fixed, i added the failing example from the issue as a
regression test.

Closes #5605
2023-07-14 11:55:05 +02:00
Chris Pryer a961f75e13
Format `assert` statement (#5168) 2023-07-14 09:01:33 +02:00
Charlie Marsh 5a4516b812
Misc. stylistic changes from flipping through rules late at night (#5757)
## Summary

This is really bad PR hygiene, but a mix of: using `Locator`-based fixes
in a few places (in lieu of `Generator`-based fixes), using match syntax
to avoid `.len() == 1` checks, using common helpers in more places, etc.

## Test Plan

`cargo test`
2023-07-14 05:23:47 +00:00
Charlie Marsh 875e04e369
Avoid removing raw strings in comparison fixes (#5755)
## Summary

Use `Locator`-based verbatim fix rather than a `Generator`-based fix,
which loses trivia (and raw strings).

Closes https://github.com/astral-sh/ruff/issues/4130.
2023-07-14 04:27:46 +00:00
Charlie Marsh af2a087806
Ignore `Enum`-and-`str` subclasses for slots enforcement (#5749)
## Summary

Matches the behavior of the upstream plugin.

Closes #5748.
2023-07-13 20:12:16 +00:00
Charlie Marsh 51a313cca4
Avoid stack overflow for non-BitOr binary types (#5743)
## Summary

Closes #5742.
2023-07-13 14:23:40 -04:00
skykasko 48309cad08
Fix the example for blank-line-before-class (D211) (#5746)
The example for
[D211](https://beta.ruff.rs/docs/rules/blank-line-before-class/) is
currently identical to the example for
[D203](https://beta.ruff.rs/docs/rules/one-blank-line-before-class/). It
should be the opposite, with the incorrect case having a blank line
before the class docstring and the correct case having no blank line.
2023-07-13 17:47:01 +00:00
Charlie Marsh 2c2e5b2704
Add some additional Option links to the docs (#5745) 2023-07-13 13:46:17 -04:00
eggplants 06a04c10e2
Fix `Options` section of rule docs (#5741)
## Summary

Fix: #5740

A trailing line-break are needed for the anchor.

## Test Plan

http://127.0.0.1:8000/docs/rules/line-too-long/#options

|before|after|
|--|--|

|![image](https://github.com/astral-sh/ruff/assets/42153744/8cb9dcce-aeda-4255-b21e-ab11817ba9e1)|![image](https://github.com/astral-sh/ruff/assets/42153744/b68d4fd7-da5a-4494-bb95-f7792f1a42db)|
2023-07-13 17:25:54 +00:00
Justin Prieto 25e491ad6f
[`flake8-pyi`] Implement PYI041 (#5722)
## Summary

Implements PYI041 from flake8-pyi. See [original
code](2a86db8271/pyi.py (L1283)).

This check only applies to function parameters in order to avoid issues
with mypy. See https://github.com/PyCQA/flake8-pyi/issues/299.

ref: #848

## Test Plan

Snapshots, manual runs of flake8.
2023-07-13 16:48:17 +00:00
Charlie Marsh e7b059cc5c
Fix nested lists in CONTRIBUTING.md (#5721)
## Summary

We have a lot of two-space-indented stuff, but apparently it needs to be
four-space indented to render as expected in MkDocs.
2023-07-13 16:32:59 +00:00
Micha Reiser 5dd5ee0c5b
Properly group assignment targets (#5728) 2023-07-13 16:00:49 +02:00
Dhruv Manilawala cf48ad7b21
Consider single element subscript expr for implicit optional (#5717)
## Summary

Consider single element subscript expr for implicit optional.

On `main`, the cases where there is only a single element in the
subscript
list was giving false positives such as for the following:

```python
typing.Union[None]
typing.Literal[None]
```

## Test Plan

`cargo test`

---------

Co-authored-by: Charlie Marsh <charlie.r.marsh@gmail.com>
2023-07-13 13:10:07 +00:00
Dhruv Manilawala f44acc047a
Check for `Any` in other types for `ANN401` (#5601)
## Summary

Check for `Any` in other types for `ANN401`. This reuses the logic from
`implicit-optional` rule to resolve the type to `Any`.

Following types are supported:
* `Union[Any, ...]`
* `Any | ...`
* `Optional[Any]`
* `Annotated[<any of the above variant>, ...]`
* Forward references i.e., `"Any | ..."`

## Test Plan

Added test cases for various combinations.

fixes: #5458
2023-07-13 18:19:27 +05:30
Tom Kuson 8420008e79
Avoid checking `EXE001` and `EXE002` on WSL (#5735)
## Summary

Do not raise `EXE001` and `EXE002` if WSL is detected. Uses the
[`wsl`](https://crates.io/crates/wsl) crate.

Closes #5445.

## Test Plan

`cargo test`

I don't use Windows, so was unable to test on a WSL environment. It
would be good if someone who runs Windows could check the functionality.
2023-07-13 07:36:07 -04:00
Charlie Marsh 932c9a4789
Extend PEP 604 rewrites to support some quoted annotations (#5725)
## Summary

Python doesn't allow `"Foo" | None` if the annotation will be evaluated
at runtime (see the comments in the PR, or the semantic model
documentation for more on what this means and when it is true), but it
_does_ allow it if the annotation is typing-only.

This, for example, is invalid, as Python will evaluate `"Foo" | None` at
runtime in order to
populate the function's `__annotations__`:

```python
def f(x: "Foo" | None): ...
```

This, however, is valid:

```python
def f():
    x: "Foo" | None
```

As is this:

```python
from __future__ import annotations

def f(x: "Foo" | None): ...
```

Closes #5706.
2023-07-13 07:34:04 -04:00
konsti 549173b395
Fix `StmtAnnAssign` formatting by mirroring `StmtAssign` (#5732)
## Summary

`StmtAnnAssign` would not insert parentheses when breaking the same way
`StmtAssign` does, causing unstable formatting and likely some syntax
errors.

## Test Plan

I added a regression test.
2023-07-13 10:51:25 +00:00
konsti 68e0f97354
Formatter: Better f-string dummy (#5730)
## Summary

The previous dummy was causing instabilities since it turned a string
into a variable.

E.g.
```python
            script_header_dict[
                "slurm_partition_line"
            ] = f"#SBATCH --partition {resources.queue_name}"
```
has an instability as
```python
-            script_header_dict["slurm_partition_line"] = (
-                NOT_YET_IMPLEMENTED_ExprJoinedStr
-            )
+            script_header_dict[
+                "slurm_partition_line"
+            ] = NOT_YET_IMPLEMENTED_ExprJoinedStr
```

## Test Plan

The instability is gone, otherwise it's still a dummy
2023-07-13 09:27:25 +00:00
Dhruv Manilawala e9771c9c63
Ignore Jupyter Notebooks for `--add-noqa` (#5727) 2023-07-13 13:26:47 +05:30
Micha Reiser 067b2a6ce6
Pass parent to `NeedsParentheses` (#5708) 2023-07-13 08:57:29 +02:00
Charlie Marsh 30702c2977
Flatten nested tuples when fixing UP007 violations (#5724)
## Summary

Also upgrading these to "Suggested" from "Manual" (they should've always
been "Suggested", I think), and adding some more test cases.
2023-07-13 04:11:32 +00:00
Charlie Marsh 34b79ead3d
Use Locator-based replacement rather than Generator for UP007 (#5723)
## Summary

Locator-based replacement is generally preferable as we get verbatim
fixes.
2023-07-13 03:50:16 +00:00
Justin Prieto 19f475ae1f
[`flake8-pyi`] Implement PYI036 (#5668)
## Summary

Implements PYI036 from `flake8-pyi`. See [original
code](https://github.com/PyCQA/flake8-pyi/blob/main/pyi.py#L1585)

## Test Plan

- Updated snapshots
- Checked against manual runs of flake8

ref: #848
2023-07-13 02:50:00 +00:00
Tom Kuson 2b03bd18f4
Implement Pylint `consider-using-in` (#5193)
## Summary

Implement Pylint rule [`consider-using-in`
(`R1714`)](https://pylint.pycqa.org/en/latest/user_guide/messages/refactor/consider-using-in.html)
as `repeated-equality-comparison-target` (`PLR1714`). This rule checks
for expressions that can be re-written as a membership test for better
readability and performance.

For example,

```python
foo == "bar" or foo == "baz" or foo == "qux"
```

should be rewritten as

```python
foo in {"bar", "baz", "qux"}
```

Related to #970. Includes documentation.

### Implementation quirks

The implementation does not work with Yoda conditions (e.g., `"a" ==
foo` instead of `foo == "a"`). The Pylint version does. I couldn't find
a way of supporting Yoda-style conditions without it being inefficient,
so didn't (I don't think people write Yoda conditions any way).

## Test Plan

Added fixture.

`cargo test`
2023-07-13 01:32:34 +00:00
Charlie Marsh c87faca884
Use `Cursor` for shebang parsing (#5716)
## Summary

Better to leverage the shared functionality we get from `Cursor`. It's
also a little bit faster, which is very cool.
2023-07-12 21:22:09 +00:00
Charlie Marsh 6dbc6d2e59
Use shared `Cursor` across crates (#5715)
## Summary

We have two `Cursor` implementations. This PR moves the implementation
from the formatter into `ruff_python_whitespace` (kind of a poorly-named
crate now) and uses it for both use-cases.
2023-07-12 21:09:27 +00:00
Charlie Marsh 0ead9a16ac
Bump version to 0.0.278 (#5714) 2023-07-12 12:39:56 -04:00
Micha Reiser 653429bef9
Handle right parens in join comma builder (#5711) 2023-07-12 18:21:28 +02:00
konsti f0aa6bd4d3
Document ruff_dev and format_dev (#5648)
## Summary

Document all `ruff_dev` subcommands and document the `format_dev` flags
in the formatter readme.

CC @zanieb please flag everything that isn't clear or missing

## Test Plan

n/a
2023-07-12 16:18:22 +02:00
Zanie 0666added9
Add RUF016: Detection of invalid index types (#5602)
Detects invalid types for tuple, list, bytes, string indices.

For example, the following will raise a `TypeError` at runtime and when
imported Python will display a `SyntaxWarning`

```python
var = [1, 2, 3]["x"]
```

```
example.py:1: SyntaxWarning: list indices must be integers or slices, not str; perhaps you missed a comma?
  var = [1, 2, 3]["x"]
Traceback (most recent call last):
  File "example.py", line 1, in <module>
    var = [1, 2, 3]["x"]
          ~~~~~~~~~^^^^^
TypeError: list indices must be integers or slices, not str
```

Previously, Ruff would not report the invalid syntax but now a violation
will be reported. This does not apply to cases where a variable, call,
or complex expression is used in the index — detection is roughly
limited to static definitions, which matches Python's warnings.

```
❯ ./target/debug/ruff example.py --select RUF015 --show-source --no-cache
example.py:1:17: RUF015 Indexed access to type `list` uses type `str` instead of an integer or slice.
  |
1 | var = [1, 2, 3]["x"]
  |                 ^^^ RUF015
  |
```

Closes https://github.com/astral-sh/ruff/issues/5082
xref
ffff1440d1
2023-07-12 00:23:06 -05:00
qdegraaf 7566ca8ff7
Refactor `repeated_keys()` to use `ComparableExpr` (#5696)
## Summary

Replaces `DictionaryKey` enum with the more general `ComparableExpr`
when checking for duplicate keys

## Test Plan

Added test fixture from issue. Can potentially be expanded further
depending on what exactly we want to flag (e.g. do we also want to check
for unhashable types?) and which `ComparableExpr::XYZ` types we consider
literals.

## Issue link

Closes: https://github.com/astral-sh/ruff/issues/5691
2023-07-12 03:46:53 +00:00
Charlie Marsh 5dd9e56748
Misc. tweaks to bandit documentation (#5701) 2023-07-11 23:32:15 -04:00
Tom Kuson f8173daf4c
Add documentation to the `S3XX` rules (#5592)
## Summary

Add documentation to the `S3XX` rules (the `flake8-bandit`
['blacklists'](https://bandit.readthedocs.io/en/latest/plugins/index.html#plugin-id-groupings)
rule group). Related to #2646 .

Changed the `lxml`-based message to reflect that [`defusedxml` doesn't
support `lxml`](https://github.com/tiran/defusedxml/issues/31).

## Test Plan

`python scripts/check_docs_formatted.py && mkdocs serve`
2023-07-11 18:56:51 -05:00
Charlie Marsh 511ec0d7bc
Refactor shebang parsing to remove regex dependency (#5690)
## Summary

Similar to #5567, we can remove the use of regex, plus simplify the
representation (use `Option`), add snapshot tests, etc.

This is about 100x faster than using a regex for cases that match (2.5ns
vs. 250ns). It's obviously not a hot path, but I prefer the consistency
with other similar comment-parsing. I may DRY these up into some common
functionality later on.
2023-07-11 16:30:38 -04:00
Micha Reiser 30bec3fcfa
Only omit optinal parens if the expression ends or starts with a parenthesized expression
<!--
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 matches Black' behavior where it only omits the optional parentheses if the expression starts or ends with a parenthesized expression:

```python
a + [aaa, bbb, cccc] * c # Don't omit
[aaa, bbb, cccc] + a * c # Split
a + c * [aaa, bbb, ccc] # Split 
```

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

## Test Plan

This improves the Jaccard index from 0.945 to 0.946
2023-07-11 17:05:25 +02:00
Micha Reiser 8b9193ab1f
Improve comprehension line break beheavior
<!--
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 improves the Black compatibility when it comes to breaking comprehensions. 

We want to avoid line breaks before the target and `in` whenever possible. Furthermore, `if X is not None` should be grouped together, similar to other binary like expressions

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

## Test Plan

`cargo test`

<!-- How was it tested? -->
2023-07-11 16:51:24 +02:00
konsti 62a24e1028
Format `ModExpression` (#5689)
## Summary

We don't use `ModExpression` anywhere but it's part of the AST, removes
one `not_implemented_yet` and is a trivial 2-liner, so i implemented
formatting for `ModExpression`.

## Test Plan

None, this kind of node does not occur in file input. Otherwise all the
tests for expressions
2023-07-11 16:41:10 +02:00
Micha Reiser f1d367655b
Format `target: annotation = value?` expressions (#5661) 2023-07-11 16:40:28 +02:00
konsti 0c8ec80d7b
Change lambda dummy to NOT_YET_IMPLEMENTED_lambda (#5687)
This only changes the dummy to be easier to identify.
2023-07-11 13:16:18 +00:00
Micha Reiser df15ad9696
Print files that are slow to format (#5681)
Co-authored-by: konsti <konstin@mailbox.org>
2023-07-11 13:03:18 +00:00
Micha Reiser 8665a1a19d
Pass `FormatContext` to `NeedsParentheses`
<!--
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

I started working on this because I assumed that I would need access to options inside of `NeedsParantheses` but it then turned out that I won't. 
Anyway, it kind of felt nice to pass fewer arguments. So I'm gonna put this out here to get your feedback if you prefer this over passing individual fiels. 

Oh, I sneeked in another change. I renamed `context.contents` to `source`. `contents` is too generic and doesn't tell you anything. 

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

## Test Plan

It compiles
2023-07-11 14:28:50 +02:00
Micha Reiser 9a8ba58b4c
Remove `mode` from `BestFitting`
<!--
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 removes the `mode` field from `BestFitting` because it is no longer used (we now use `conditional_group` and `fits_expanded).

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

## Test Plan

`cargo test`

<!-- How was it tested? -->
2023-07-11 14:19:26 +02:00
Micha Reiser 715250a179
Prefer expanding parenthesized expressions before operands
<!--
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 implements Black's behavior where it first splits off parenthesized expressions before splitting before operands to avoid unnecessary parentheses:

```python
# We want 
if a + [ 
	b,
	c
]: 
	pass

# Rather than
if (
    a
    + [b, c]
): 
	pass
```

This is implemented by using the new IR elements introduced in #5596. 

* We give the group wrapping the optional parentheses an ID (`parentheses_id`)
* We use `conditional_group` for the lower priority groups  (all non-parenthesized expressions) with the condition that the `parentheses_id` group breaks (we want to split before operands only if the parentheses are necessary)
* We use `fits_expanded` to wrap all other parenthesized expressions (lists, dicts, sets), to prevent that expanding e.g. a list expands the `parentheses_id` group. We gate the `fits_expand` to only apply if the `parentheses_id` group fits (because we  prefer `a\n+[b, c]` over expanding `[b, c]` if the whole expression gets parenthesized).

We limit using `fits_expanded` and `conditional_group` only to expressions that themselves are not in parentheses (checking the conditions isn't free)

## Test Plan

It increases the Jaccard index for Django from 0.915 to 0.917

## Incompatibilites

There are two incompatibilities left that I'm aware of (there may be more, I didn't go through all snapshot differences). 

### Long string literals
I  commented on the regression. The issue is that a very long string (or any content without a split point) may not fit when only breaking the right side. The formatter than inserts the optional parentheses. But this is kind of useless because the overlong string will still not fit, because there are no new split points. 

I think we should ignore this incompatibility for now


### Expressions on statement level

I don't fully understand the logic behind this yet, but black doesn't break before the operators for the following example even though the expression exceeds the configured line width

```python
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa < bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb > ccccccccccccccccccccccccccccc == ddddddddddddddddddddd
```

But it would if the expression is used inside of a condition. 

What I understand so far is that Black doesn't insert optional parentheses on the expression statement level (and a few other places) and, therefore, only breaks after opening parentheses. I propose to keep this deviation for now to avoid overlong-lines and use the compatibility report to make a decision if we should implement the same behavior.
2023-07-11 14:07:39 +02:00
Micha Reiser d30e9125eb
Extend formatter IR to support Black's expression formatting (#5596) 2023-07-11 11:20:04 +00:00