Commit Graph

542 Commits

Author SHA1 Message Date
Charlie Marsh
4dcf284a04 Index source code upfront to power (row, column) lookups (#1990)
## Summary

The problem: given a (row, column) number (e.g., for a token in the AST), we need to be able to map it to a precise byte index in the source code. A while ago, we moved to `ropey` for this, since it was faster in practice (mostly, I think, because it's able to defer indexing). However, at some threshold of accesses, it becomes faster to index the string in advance, as we're doing here.

## Benchmark

It looks like this is ~3.6% slower for the default rule set, but ~9.3% faster for `--select ALL`.

**I suspect there's a strategy that would be strictly faster in both cases**, based on deferring even more computation (right now, we lazily compute these offsets, but we do it for the entire file at once, even if we only need some slice at the top), or caching the `ropey` lookups in some way.

Before:

![main](https://user-images.githubusercontent.com/1309177/213883581-8f73c61d-2979-4171-88a6-a88d7ff07e40.png)

After:

![48 all](https://user-images.githubusercontent.com/1309177/213883586-3e049680-9ef9-49e2-8f04-fd6ff402eba7.png)

## Alternatives

I tried tweaking the `Vec::with_capacity` hints, and even trying `Vec::with_capacity(str_indices::lines_crlf::count_breaks(contents))` to do a quick scan of the number of lines, but that turned out to be slower.
2023-01-21 17:56:11 -05:00
Zeddicus414
08fc9b8095 ICN001 check from imports that have no alias (#2072)
Add tests.

Ensure that these cases are caught by ICN001:
```python
from xml.dom import minidom
from xml.dom.minidom import parseString
```

with config:
```toml
[tool.ruff.flake8-import-conventions.extend-aliases]
"dask.dataframe" = "dd"
"xml.dom.minidom" = "md"
"xml.dom.minidom.parseString" = "pstr"
```
2023-01-21 17:47:08 -05:00
Zeddicus414
5726118cfe ICN001 import-alias-is-not-conventional should check "from" imports (#2070)
Closes https://github.com/charliermarsh/ruff/issues/2047.
2023-01-21 15:43:51 -05:00
Simon Brugman
67de8ac85e feat: implementation for TRY004 (#2066)
See: #2056.
2023-01-21 14:58:59 -05:00
Charlie Marsh
fbee95a668 Avoid flagging redefined imports as unused in same-scope (#2065)
This is effectively a revert of #1173, to favor false-negatives over false-positives in the same-scope case.

Closes #2044.
2023-01-21 12:50:21 -05:00
Simon Brugman
afcf5c0ee0 feat: plugin scaffold for tryceratops with TRY300 (#2055)
Renamed to TRY to avoid conflicts, as proposed in https://github.com/guilatrova/tryceratops/pull/55

https://github.com/guilatrova/tryceratops/blob/main/docs/violations/TC300.md

See: #2056
2023-01-21 11:25:10 -05:00
Maksudul Haque
0c30768288 [flake8-builtins] Add builtins-ignorelist Option (#2061)
Closes #2053.
2023-01-21 11:09:04 -05:00
Colin Delahunty
80295f335b Pyupgrade: Printf string formatting (#1803) 2023-01-21 09:37:22 -05:00
Charlie Marsh
38eed292e4 Avoid removing comments in RUF005 (#2057)
Closes #2054.
2023-01-21 07:37:25 -05:00
Harutaka Kawamura
eb1b5e5454 De-duplicate SIM102 (#2050)
The idea is the same as #1867. Avoids emitting `SIM102` twice for the following code:

```python
if a:
    if b:
        if c:
            d
```

```
resources/test/fixtures/flake8_simplify/SIM102.py:1:1: SIM102 Use a single `if` statement instead of nested `if` statements
resources/test/fixtures/flake8_simplify/SIM102.py:2:5: SIM102 Use a single `if` statement instead of nested `if` statements
```
2023-01-20 23:38:52 -05:00
Charlie Marsh
8e558a3458 Add scaffolding for flake8-type-checking extension (#2048)
This PR adds the scaffolding files for `flake8-type-checking`, along with the simplest rule (`empty-type-checking-block`), just as an example to get us started.

See: #1785.
2023-01-20 22:41:36 -05:00
Simon Brugman
608b2191aa [flake8-executable] EXE003-005 (#2023)
Tracking issue: https://github.com/charliermarsh/ruff/issues/2024

Implementation for EXE003, EXE004 and EXE005 of `flake8-executable` 
(shebang should contain "python", not have whitespace before, and should be on the first line)

Please take in mind that this is my first rust contribution.

The remaining EXE-rules are a combination of shebang (`lines.rs`), file permissions (`fs.rs`) and if-conditions (`ast.rs`). I was not able to find other rules that have interactions/dependencies in them. Any advice on how this can be best implemented would be very welcome.

For autofixing `EXE005`, I had in mind to _move_  the shebang line to the top op the file. This could be achieved by a combination of `Fix::insert` and `Fix::delete` (multiple fixes per diagnostic), or by implementing a dedicated `Fix::move`, or perhaps in other ways. For now I've left it out, but keen on hearing what you think would be most consistent with the package, and pointer where to start (if at all).

---
If you care about another testimonial:
`ruff` not only helps staying on top of the many excellent flake8 plugins and other Python code quality tools that are available, it also applies them at baffling speed.
(Planning to implement it soon for github.com/pandas-profiling/pandas-profiling (as largest contributor) and github.com/ing-bank/popmon.)
2023-01-20 18:19:07 -05:00
Eric Roberts
3939c2dbf7 Add support for pycodestyle E101 (#2038)
Rule described here: https://www.flake8rules.com/rules/E101.html

I tried to follow contributing guidelines closely, I've never worked with Rust before. Stumbled across Ruff a few days ago and would like to use it in our project, but we use a bunch of flake8 rules that are not yet implemented in ruff, so I decided to give it a go.
2023-01-20 17:24:58 -05:00
Charlie Marsh
9e704a7c63 Only fix true-false returns for return-bool-condition-directly (#2037)
Closes #2035.
2023-01-20 13:17:19 -05:00
Zeddicus414
c9da98e0b7 Fix D404 NoThisPrefix not working with whitespace. (#2036)
D404 should trigger for """ This is a docstring."""

Add a few tests to ensure the fix worked.
2023-01-20 13:01:31 -05:00
Florian Best
db8e4500ee fix(pydocstyle): Avoid trimming docstring if starts with leading quote (#2027)
Fixes: #2017

looks like the other way round is also possible to break:

```""" "foo"""`
2023-01-20 09:57:48 -05:00
Ville Skyttä
4bdf506d80 Grammar fixes (#2014) 2023-01-20 07:44:23 -05:00
Charlie Marsh
4af2353ef9 Avoid trimming docstring if ends in trailing quote (#2025)
Closes #2017.
2023-01-20 07:41:58 -05:00
Aarni Koskela
bea6deb0c3 Port pydocstyle code 401 (ImperativeMood) (#1999)
This adds support for pydocstyle code D401 using the `imperative` crate.
2023-01-20 07:18:27 -05:00
Colin Delahunty
81db00a3c4 Pyupgrade: Extraneous parenthesis (#1926) 2023-01-20 00:04:07 -05:00
Charlie Marsh
8a8939afd8 Avoid checking row types for single-name @parametrize decorators (#2013)
Closes #2008.
2023-01-19 22:13:17 -05:00
Charlie Marsh
ec0c7647ab Avoid SIM401 in elif blocks (#2012)
For now, we're just gonna avoid flagging this for `elif` blocks, following the same reasoning as for ternaries. We can handle all of these cases, but we'll knock out the TODOs as a pair, and this avoids broken code.

Closes #2007.
2023-01-19 21:57:18 -05:00
Charlie Marsh
f6a93a4c3d Enable autofix for FitsOnOneLine (D200) (#2006)
Closes #1965.
2023-01-19 19:24:50 -05:00
Aarni Koskela
de54ff114e Add RUF005 "unpack instead of concatenating" check (#1957)
This PR adds a new check that turns expressions such as `[1, 2, 3] + foo` into `[1, 2, 3, *foo]`, since the latter is easier to read and faster:

```
~ $ python3.11 -m timeit -s 'b = [6, 5, 4]' '[1, 2, 3] + b'
5000000 loops, best of 5: 81.4 nsec per loop
~ $ python3.11 -m timeit -s 'b = [6, 5, 4]' '[1, 2, 3, *b]'
5000000 loops, best of 5: 66.2 nsec per loop
```

However there's a couple of gotchas:

* This felt like a `simplify` rule, so I borrowed an unused `SIM` code even if the upstream `flake8-simplify` doesn't do this transform. If it should be assigned some other code, let me know 😄 
* **More importantly** this transform could be unsafe if the other operand of the `+` operation has overridden `__add__` to do something else. What's the `ruff` policy around potentially unsafe operations? (I think some of the suggestions other ported rules give could be semantically different from the original code, but I'm not sure.)
* I'm not a very established Rustacean, so there's no doubt my code isn't quite idiomatic. (For instance, is there a neater way to write that four-way `match` statement?)

Thanks for `ruff`, by the way! :)
2023-01-19 17:38:17 -05:00
Charlie Marsh
ad80fdc2cd Avoid SIM201 and SIM202 errors in __ne__ et al (#2001)
Closes #1986.
2023-01-19 11:27:27 -05:00
Charlie Marsh
a122d95ef5 Preserve unmatched comparators in SIM109 (#1998)
Closes #1993.
2023-01-19 10:23:20 -05:00
Charlie Marsh
d33424ec9d Enable suppression of magic values by type (#1987)
Closes #1949.
2023-01-18 20:44:24 -05:00
Charlie Marsh
34412a0a01 Avoid removing side effects for boolean simplifications (#1984)
Closes #1978.
2023-01-18 19:08:14 -05:00
Charlie Marsh
969a6f0d53 Replace misplaced-comparison-constant with SIM300 (#1980)
Closes: #1954.
2023-01-18 18:42:49 -05:00
Charlie Marsh
1ab0273aa7 Strip whitespace when injecting D209 newline (#1967)
Closes #1963.
2023-01-18 12:09:17 -05:00
Charlie Marsh
5a7d8c25f4 Treat subscript accesses as unsafe effects for autofix (#1966)
See: #1809.
2023-01-18 11:46:12 -05:00
Maksudul Haque
9a3e525930 [isort] Add no-lines-before Option (#1955)
Closes https://github.com/charliermarsh/ruff/issues/1916.
2023-01-18 11:09:47 -05:00
Anders Kaseorg
b9c6cfc0ab Autofix SIM117 (MultipleWithStatements) (#1961)
This is slightly buggy due to Instagram/LibCST#855; it will complain `[ERROR] Failed to fix nested with: Failed to extract CST from source` when trying to fix nested parenthesized `with` statements lacking trailing commas. But presumably people who write parenthesized `with` statements already knew that they don’t need to nest them.

Signed-off-by: Anders Kaseorg <andersk@mit.edu>
2023-01-18 11:06:04 -05:00
Charlie Marsh
b1f10c8339 Confine type-of-primitive checks to builtin type calls (#1962)
Closes #1958.
2023-01-18 10:53:50 -05:00
Anders Kaseorg
83346de6e0 Autofix SIM102 (NestedIfStatements)
Co-authored-by: Charlie Marsh <charlie.r.marsh@gmail.com>
Signed-off-by: Anders Kaseorg <andersk@mit.edu>
2023-01-18 07:37:27 -05:00
Maksudul Haque
868d0b3e29 [isort] Add constants and variables Options (#1951)
closes https://github.com/charliermarsh/ruff/issues/1819
2023-01-18 07:30:51 -05:00
Anders Kaseorg
ea4d54a90f Restrict SIM105 to try blocks with a body of one simple statement (#1948)
If a `try` block has multiple statements, a compound statement, or
control flow, rewriting it with `contextlib.suppress` would obfuscate
the fact that the exception still short-circuits further statements in
the block.

Fixes #1947.

Signed-off-by: Anders Kaseorg <andersk@mit.edu>
2023-01-18 00:22:22 -05:00
Charlie Marsh
51b917cfbf Exempt contextlib.ExitStack() for SIM115 rules (#1946)
Since our binding tracking is somewhat limited, I opted to favor false negatives over false positives. So, e.g., this won't trigger SIM115:

```py
with contextlib.ExitStack():
    f = exit_stack.enter_context(open("filename"))
```

(Notice that `exit_stack` is unbound.)

The alternative strategy required us to incorrectly trigger SIM115 on this:

```py
with contextlib.ExitStack() as exit_stack:
    exit_stack_ = exit_stack
    f = exit_stack_.enter_context(open("filename"))
```

Closes #1945.
2023-01-17 22:39:54 -05:00
Edgar R. M
c880d744fd Implement flake8-no-pep420 (#1942)
Closes https://github.com/charliermarsh/ruff/issues/1844.
2023-01-17 22:10:32 -05:00
Charlie Marsh
84d1df08be Avoid broken autofix for SIM103 with elif (#1944)
Also adjusts the generator to avoid the extra parentheses (and skips commented `if` statements).

Closes #1943.
2023-01-17 22:03:17 -05:00
Charlie Marsh
072849a8a9 Move @functools.cache rewrites to their own rule (#1938)
Closes #1934.
2023-01-17 15:12:40 -05:00
Charlie Marsh
70ea4b25e8 Allow duplicate enum values for enum.auto() (#1933)
Closes #1932.
2023-01-17 11:14:11 -05:00
Colin Delahunty
1730f2a603 [pyupgrade] Automatically rewrite format-strings to f-strings (#1905) 2023-01-16 23:06:39 -05:00
Charlie Marsh
a4862857de Update PIE796 fixture 2023-01-16 19:29:14 -05:00
Leonardo Esparis
6e88c60c46 Add flake8-pie PIE796: prefer-unique-enum (#1923)
I accept any suggestion. By the way, I have a doubt, I have checked and all flake8-pie plugins can be fixed by ruff, but is it necessary that this one is also fixed automatically ?

rel #1543
2023-01-16 19:27:34 -05:00
Charlie Marsh
f3bf008aed Avoid removing statements that contain side-effects (#1920)
Closes #1917.
2023-01-16 14:45:02 -05:00
Charlie Marsh
6abf71639f Avoid syntax errors when fixing parenthesized unused variables (#1919)
Closes #1917.
2023-01-16 14:27:41 -05:00
Charlie Marsh
15403522c1 Avoid triggering SIM117 for async with statements (#1903)
Actually, it looks like _none_ of the existing rules should be triggered on async `with` statements.

Closes #1902.
2023-01-15 21:42:36 -05:00
Charlie Marsh
7608087776 Don't require docstrings for setters and deleters (#1899) 2023-01-15 18:57:38 -05:00
Ran Benita
d3041587ad Implement flake8-commas (#1872)
Implements [flake8-commas](https://github.com/PyCQA/flake8-commas). Fixes #1058.

The plugin is mostly redundant with Black (and also deprecated upstream), but very useful for projects which can't/won't use an auto-formatter. 

This linter works on tokens. Before porting to Rust, I cleaned up the Python code ([link](https://gist.github.com/bluetech/7c5dcbdec4a73dd5a74d4bc09c72b8b9)) and made sure the tests pass. In the Rust version I tried to add explanatory comments, to the best of my understanding of the original logic.

Some changes I did make:

- Got rid of rule C814 - "missing trailing comma in Python 2". Ruff doesn't support Python 2.
- Merged rules C815 - "missing trailing comma in Python 3.5+" and C816 - "missing trailing comma in Python 3.6+" into C812 - "missing trailing comma". These Python versions are outdated, didn't think it was worth the complication.
- Added autofixes for C812 and C819.

Autofix is missing for C818 - "trailing comma on bare tuple prohibited". It needs to turn e.g. `x = 1,` into `x = (1, )`, it's a bit difficult to do with tokens only, so I skipped it for now.

I ran the rules on cpython/Lib and on a big internal code base and it works as intended (though I only sampled the diffs).
2023-01-15 14:03:32 -05:00