Commit graph

1184 commits

Author SHA1 Message Date
Micha Reiser
c1cc6f3be1
Add basic Constant formatting (#4954) 2023-06-08 11:42:44 +00:00
Micha Reiser
83cf6d6e2f
Implement Binary expression without best_fitting (#4952) 2023-06-08 12:45:03 +02:00
konstin
23abad0bd5
A basic StmtAssign formatter and better dummies for expressions (#4938)
* A basic StmtAssign formatter and better dummies for expressions

The goal of this PR was formatting StmtAssign since many nodes in the black tests (and in python in general) are after an assignment. This caused unstable formatting: The spacing of power op spacing depends on the type of the two involved expressions, but each expression was formatted as dummy string and re-parsed as a ExprName, so in the second round the different rules of ExprName were applied, causing unstable formatting.

This PR does not necessarily bring us closer to black's style, but it unlocks a good porting of black's test suite and is a basis for implementing the Expr nodes.

* fmt

* Review
2023-06-08 12:20:25 +02:00
konstin
651d89794c
Use phf for confusables to reduce llvm lines (#4926)
* Use phf for confusables to reduce llvm lines

## Summary

This replaces FxHashMap for the confusables with a perfect hash map from the [phf crate](https://github.com/rust-phf/rust-phf) to reduce the generated llvm instructions.

A perfect hash function is one that doesn't have any collisions. We can build one because we know all keys at compile time. This improves hashmap efficiency, even though this is likely not noticeable in our case (except someone has a large non-english crate to test on).

The original hashmap contained a lot of duplicates, which i had to remove when phf_map complained, i did so by sorting the keys.

The important part that it reduces the llvm instructions generated (#3808, `RUSTFLAGS="-Csymbol-mangling-version=v0" cargo llvm-lines -p ruff --lib | head -20`):

```
  Lines                  Copies               Function name
  -----                  ------               -------------
  1740502                38973                (TOTAL)
    27423 (1.6%,  1.6%)      1 (0.0%,  0.0%)  ruff[cef4c65d96248843]::rules::ruff::rules::confusables::CONFUSABLES::{closure#0}
    10193 (0.6%,  2.2%)      1 (0.0%,  0.0%)  <ruff[cef4c65d96248843]::codes::RuleCodePrefix>::iter
     8107 (0.5%,  2.6%)      1 (0.0%,  0.0%)  <ruff[cef4c65d96248843]::codes::Rule>::noqa_code
     7345 (0.4%,  3.0%)      1 (0.0%,  0.0%)  <ruff[cef4c65d96248843]::checkers::ast::Checker as ruff_python_ast[3778b140caf21545]::visitor::Visitor>::visit_stmt
     6412 (0.4%,  3.4%)      1 (0.0%,  0.0%)  <<ruff[cef4c65d96248843]::settings::options::Options as serde[d89b1b632568f5a3]:🇩🇪:Deserialize>::deserialize::__Visitor as serde[d89b1b632568f5a3]:🇩🇪:Visitor>::visit_map::<toml_edit[7e3a6c5e67260672]:🇩🇪:spanned::SpannedDeserializer<toml_edit[7e3a6c5e67260672]:🇩🇪:value::ValueDeserializer>>
     6412 (0.4%,  3.8%)      1 (0.0%,  0.0%)  <<ruff[cef4c65d96248843]::settings::options::Options as serde[d89b1b632568f5a3]:🇩🇪:Deserialize>::deserialize::__Visitor as serde[d89b1b632568f5a3]:🇩🇪:Visitor>::visit_map::<toml_edit[7e3a6c5e67260672]:🇩🇪:table::TableMapAccess>
     6409 (0.4%,  4.2%)      1 (0.0%,  0.0%)  <<ruff[cef4c65d96248843]::settings::options::Options as serde[d89b1b632568f5a3]:🇩🇪:Deserialize>::deserialize::__Visitor as serde[d89b1b632568f5a3]:🇩🇪:Visitor>::visit_map::<toml_edit[7e3a6c5e67260672]:🇩🇪:datetime::DatetimeDeserializer>
     5696 (0.3%,  4.5%)      1 (0.0%,  0.0%)  <ruff[cef4c65d96248843]::checkers::ast::Checker as ruff_python_ast[3778b140caf21545]::visitor::Visitor>::visit_expr
     4448 (0.3%,  4.7%)      1 (0.0%,  0.0%)  ruff[cef4c65d96248843]::flake8_to_ruff::converter::convert
     3702 (0.2%,  4.9%)      1 (0.0%,  0.0%)  <&ruff[cef4c65d96248843]::registry::Linter as core[da82827a87f140f9]::iter::traits::collect::IntoIterator>::into_iter
     3349 (0.2%,  5.1%)      1 (0.0%,  0.0%)  <ruff[cef4c65d96248843]::registry::Linter>::code_for_rule
     3132 (0.2%,  5.3%)      1 (0.0%,  0.0%)  <ruff[cef4c65d96248843]::codes::Rule as core[da82827a87f140f9]::fmt::Debug>::fmt
     3130 (0.2%,  5.5%)      1 (0.0%,  0.0%)  <&str as core[da82827a87f140f9]::convert::From<&ruff[cef4c65d96248843]::codes::Rule>>::from
     3130 (0.2%,  5.7%)      1 (0.0%,  0.0%)  <&str as core[da82827a87f140f9]::convert::From<ruff[cef4c65d96248843]::codes::Rule>>::from
     3130 (0.2%,  5.9%)      1 (0.0%,  0.0%)  <ruff[cef4c65d96248843]::codes::Rule as core[da82827a87f140f9]::convert::AsRef<str>>::as_ref
     3128 (0.2%,  6.0%)      1 (0.0%,  0.0%)  <ruff[cef4c65d96248843]::codes::RuleIter>::get
     2669 (0.2%,  6.2%)      1 (0.0%,  0.0%)  <<ruff[cef4c65d96248843]::settings::options::Options as serde[d89b1b632568f5a3]:🇩🇪:Deserialize>::deserialize::__Visitor as serde[d89b1b632568f5a3]:🇩🇪:Visitor>::visit_seq::<toml_edit[7e3a6c5e67260672]:🇩🇪:array::ArraySeqAccess>
```
After:
```
  Lines                  Copies               Function name
  -----                  ------               -------------
  1710487                38900                (TOTAL)
    10193 (0.6%,  0.6%)      1 (0.0%,  0.0%)  <ruff[52408f46d2058296]::codes::RuleCodePrefix>::iter
     8107 (0.5%,  1.1%)      1 (0.0%,  0.0%)  <ruff[52408f46d2058296]::codes::Rule>::noqa_code
     7345 (0.4%,  1.5%)      1 (0.0%,  0.0%)  <ruff[52408f46d2058296]::checkers::ast::Checker as ruff_python_ast[5588cd60041c8605]::visitor::Visitor>::visit_stmt
     6412 (0.4%,  1.9%)      1 (0.0%,  0.0%)  <<ruff[52408f46d2058296]::settings::options::Options as serde[d89b1b632568f5a3]:🇩🇪:Deserialize>::deserialize::__Visitor as serde[d89b1b632568f5a3]:🇩🇪:Visitor>::visit_map::<toml_edit[7e3a6c5e67260672]:🇩🇪:spanned::SpannedDeserializer<toml_edit[7e3a6c5e67260672]:🇩🇪:value::ValueDeserializer>>
     6412 (0.4%,  2.2%)      1 (0.0%,  0.0%)  <<ruff[52408f46d2058296]::settings::options::Options as serde[d89b1b632568f5a3]:🇩🇪:Deserialize>::deserialize::__Visitor as serde[d89b1b632568f5a3]:🇩🇪:Visitor>::visit_map::<toml_edit[7e3a6c5e67260672]:🇩🇪:table::TableMapAccess>
     6409 (0.4%,  2.6%)      1 (0.0%,  0.0%)  <<ruff[52408f46d2058296]::settings::options::Options as serde[d89b1b632568f5a3]:🇩🇪:Deserialize>::deserialize::__Visitor as serde[d89b1b632568f5a3]:🇩🇪:Visitor>::visit_map::<toml_edit[7e3a6c5e67260672]:🇩🇪:datetime::DatetimeDeserializer>
     5696 (0.3%,  3.0%)      1 (0.0%,  0.0%)  <ruff[52408f46d2058296]::checkers::ast::Checker as ruff_python_ast[5588cd60041c8605]::visitor::Visitor>::visit_expr
     4448 (0.3%,  3.2%)      1 (0.0%,  0.0%)  ruff[52408f46d2058296]::flake8_to_ruff::converter::convert
     3702 (0.2%,  3.4%)      1 (0.0%,  0.0%)  <&ruff[52408f46d2058296]::registry::Linter as core[da82827a87f140f9]::iter::traits::collect::IntoIterator>::into_iter
     3349 (0.2%,  3.6%)      1 (0.0%,  0.0%)  <ruff[52408f46d2058296]::registry::Linter>::code_for_rule
     3132 (0.2%,  3.8%)      1 (0.0%,  0.0%)  <ruff[52408f46d2058296]::codes::Rule as core[da82827a87f140f9]::fmt::Debug>::fmt
     3130 (0.2%,  4.0%)      1 (0.0%,  0.0%)  <&str as core[da82827a87f140f9]::convert::From<&ruff[52408f46d2058296]::codes::Rule>>::from
     3130 (0.2%,  4.2%)      1 (0.0%,  0.0%)  <&str as core[da82827a87f140f9]::convert::From<ruff[52408f46d2058296]::codes::Rule>>::from
     3130 (0.2%,  4.4%)      1 (0.0%,  0.0%)  <ruff[52408f46d2058296]::codes::Rule as core[da82827a87f140f9]::convert::AsRef<str>>::as_ref
     3128 (0.2%,  4.5%)      1 (0.0%,  0.0%)  <ruff[52408f46d2058296]::codes::RuleIter>::get
     2669 (0.2%,  4.7%)      1 (0.0%,  0.0%)  <<ruff[52408f46d2058296]::settings::options::Options as serde[d89b1b632568f5a3]:🇩🇪:Deserialize>::deserialize::__Visitor as serde[d89b1b632568f5a3]:🇩🇪:Visitor>::visit_seq::<toml_edit[7e3a6c5e67260672]:🇩🇪:array::ArraySeqAccess>
     2659 (0.2%,  4.9%)      1 (0.0%,  0.0%)  <&ruff[52408f46d2058296]::codes::Pylint as core[da82827a87f140f9]::iter::traits::collect::IntoIterator>::into_iter
```

I'd assume this has a positive effect both on compile time and on runtime, but i don't know the actual effect on compile times and can't really measure.

## Test plan

Check CI for any performance regressions.

This should fix #3808 if we merge it.

* clippy

* Update update_ambiguous_characters.py
2023-06-08 08:13:20 +02:00
Micha Reiser
39a1f3980f
Upgrade RustPython (#4900) 2023-06-08 05:53:14 +00:00
Charlie Marsh
4b78141f6b
Generate one fix per statement for flake8-type-checking rules (#4915) 2023-06-07 22:22:35 -04:00
Charlie Marsh
5235977abc
Bump version to 0.0.272 (#4948) 2023-06-08 02:17:29 +00:00
kyoto7250
01d3d4bbd2
ignore if using infinite iterators in B905 (#4914) 2023-06-08 02:12:50 +00:00
Charlie Marsh
ac4a4da50e
Handle implicit string concatenations in conversion-flag rewrites (#4947) 2023-06-08 02:04:35 +00:00
Charlie Marsh
a6d269f263
Apply dict.get fix before ternary rewrite (#4944) 2023-06-07 22:33:40 +00:00
Charlie Marsh
f17282d615
Skip class scopes when resolving nonlocal references (#4943) 2023-06-07 22:25:36 +00:00
Dhruv Manilawala
6950c93934
Make C413 fix as suggested for reversed call (#4891) 2023-06-07 18:23:19 -04:00
Charlie Marsh
ae75b303f0
Avoid attributing runtime references to module-level imports (#4942) 2023-06-07 21:56:03 +00:00
Charlie Marsh
20240fc3d9
Move flake8-fixme rules to FIX prefix (#4917) 2023-06-07 21:14:49 +00:00
Micha Reiser
bcf745c5ba
Replace verbatim text with NOT_YET_IMPLEMENTED (#4904)
<!--
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 replaces the `verbatim_text` builder with a `not_yet_implemented` builder that emits `NOT_YET_IMPLEMENTED_<NodeKind>` for not yet implemented nodes. 

The motivation for this change is that partially formatting compound statements can result in incorrectly indented code, which is a syntax error:

```python
def func_no_args():
  a; b; c
  if True: raise RuntimeError
  if False: ...
  for i in range(10):
    print(i)
    continue
```

Get's reformatted to

```python
def func_no_args():
    a; b; c
    if True: raise RuntimeError
    if False: ...
    for i in range(10):
    print(i)
    continue
```

because our formatter does not yet support `for` statements and just inserts the text from the source. 

## Downsides

Using an identifier will not work in all situations. For example, an identifier is invalid in an `Arguments ` position. That's why I kept `verbatim_text` around and e.g. use it in the `Arguments` formatting logic where incorrect indentations are impossible (to my knowledge). Meaning, `verbatim_text` we can opt in to `verbatim_text` when we want to iterate quickly on nodes that we don't want to provide a full implementation yet and using an identifier would be invalid. 

## Upsides

Running this on main discovered stability issues with the newline handling that were previously "hidden" because of the verbatim formatting. I guess that's an upside :)

## Test Plan

None?
2023-06-07 14:57:25 +02:00
Addison Crump
2f125f4019
Create fuzzers for testing correctness of parsing, linting and fixing (#4822)
Co-authored-by: Micha Reiser <micha@reiser.io>
2023-06-07 14:57:07 +02:00
Micha Reiser
6ab3fc60f4
Correctly handle newlines after/before comments (#4895)
<!--
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 issue fixes the removal of empty lines between a leading comment and the previous statement:

```python
a  = 20

# leading comment
b = 10
```

Ruff removed the empty line between `a` and `b` because:
* The leading comments formatting does not preserve leading newlines (to avoid adding new lines at the top of a body)
* The `JoinNodesBuilder` counted the lines before `b`, which is 1 -> Doesn't insert a new line

This is fixed by changing the `JoinNodesBuilder` to count the lines instead *after* the last node. This correctly gives 1, and the `# leading comment` will insert the empty lines between any other leading comment or the node.



## Test Plan

I added a new test for empty lines.
2023-06-07 14:49:43 +02:00
Charlie Marsh
ec609f5c3b
Clarify requires-python inference requirements (#4918) 2023-06-07 04:18:56 +00:00
Justin Prieto
b9060ea2bd
[flake8-pyi] Implement PYI050 (#4884) 2023-06-07 01:56:53 +00:00
Charlie Marsh
b56a799417
Add some more test coverage for del statements (#4913) 2023-06-06 21:40:23 -04:00
Charlie Marsh
780d153ae8
Replace one-off locals property with ScopeFlags (#4912) 2023-06-06 21:22:21 -04:00
Tom Kuson
7cc205b5d6
Change iteration-over-set to flag set literals only (#4907) 2023-06-06 21:06:46 +00:00
Charlie Marsh
2a6d7cd71c
Avoid no-op fix for nested with expressions (#4906) 2023-06-06 20:15:21 +00:00
Charlie Marsh
2b5fb70482
Bump version to 0.0.271 (#4890) 2023-06-06 15:11:48 -04:00
Charlie Marsh
8c048b463c
Track symbol deletions separately from bindings (#4888) 2023-06-06 18:49:36 +00:00
Micha Reiser
19abee086b
Introduce AnyFunctionDefinition Node (#4898) 2023-06-06 20:37:46 +02:00
Addison Crump
1ed5d7e437
mark f522 as sometimes fixable (#4893) 2023-06-06 09:14:23 -04:00
Micha Reiser
3f032cf09d
Format binary expressions (#4862)
* Format Binary Expressions

* Extract NeedsParentheses trait
2023-06-06 08:34:53 +00:00
Charlie Marsh
7b0fb1a3b4
Respect noqa directives on ImportFrom parents for type-checking rules (#4889) 2023-06-06 02:37:07 +00:00
Charlie Marsh
c2a3e97b7f
Avoid early-exit in explicit-f-string-type-conversion (#4886) 2023-06-06 00:52:11 +00:00
Charlie Marsh
805b2eb0b7
Respect shadowed exports in __all__ (#4885) 2023-06-05 20:48:53 -04:00
Charlie Marsh
0c7ea800af
Remove destructive fixes for F523 (#4883) 2023-06-06 00:44:30 +00:00
Charlie Marsh
c67029ded9
Move duplicate-value rule to flake8-bugbear (#4882) 2023-06-05 21:43:47 +00:00
Charlie Marsh
a70afa7de7
Remove ToString prefixes (#4881) 2023-06-05 21:11:19 +00:00
Charlie Marsh
d1b8fe6af2
Fix round-tripping of nested functions (#4875) 2023-06-05 16:13:08 -04:00
Micha Reiser
913b9d1fcf
Normalize newlines in verbatim_text (#4850) 2023-06-05 19:30:28 +00:00
Justin Prieto
f9e82f2578
[flake8-pyi] Implement PYI029 (#4851) 2023-06-05 19:21:16 +00:00
Charlie Marsh
79ae1840af
Remove unused lifetime from UnusedImport type alias (#4874) 2023-06-05 19:09:27 +00:00
Charlie Marsh
8938b2d555
Use qualified_name terminology in more structs for consistency (#4873) 2023-06-05 19:06:48 +00:00
Micha Reiser
33434fcb9c
Add Formatter benchmark (#4860) 2023-06-05 21:05:42 +02:00
Charlie Marsh
8a3a269eef
Avoid index-out-of-bands panic for positional placeholders (#4872) 2023-06-05 18:31:47 +00:00
Charlie Marsh
d31eb87877
Extract shared simple AST node inference utility (#4871) 2023-06-05 18:23:37 +00:00
Ryan Yang
72245960a1
implement E307 for pylint invalid str return type (#4854) 2023-06-05 17:54:15 +00:00
Charlie Marsh
e6b00f0c4e
Avoid running RUF100 rules when code contains syntax errors (#4869) 2023-06-05 17:32:06 +00:00
Charlie Marsh
f952bef1ad
Mark F523 as "sometimes" fixable (#4868) 2023-06-05 16:55:28 +00:00
Allison Karlitskaya
dc223fd3ca
Add some exceptions for FBT003 (#3247) (#4867) 2023-06-05 16:44:49 +00:00
konstin
209aaa5add
Ensure type_ignores for Module are empty (#4861)
According to https://docs.python.org/3/library/ast.html#ast-helpers, we expect type_ignores to be always be empty, so this adds a debug assert.

Test plan: I confirmed that the assertion holdes for the file below and for all the black tests which include a number of `type: ignore` comments.
```python
# type: ignore

if 1:
    print("1")  # type: ignore
    # elsebranch

# type: ignore

else:  # type: ignore
    print("2")  # type: ignore

while 1:
    print()

# type: ignore
```
2023-06-05 11:38:08 +02:00
konstin
ff37d7af23
Implement module formatting using JoinNodesBuilder (#4808)
* Implement module formatting using JoinNodesBuilder

This uses JoinNodesBuilder to implement module formatting for #4800

See the snapshots for the changed behaviour. See one PR up for a CLI that i used to verify the trailing new line behaviour
2023-06-05 08:35:05 +00:00
Micha Reiser
c65f47d7c4
Format while Statement (#4810) 2023-06-05 08:24:00 +00:00
konstin
d1d06960f0
Add a formatter CLI for debugging (#4809)
* Add a formatter CLI for debugging

This adds a ruff_python_formatter cli modelled aber `rustfmt` that i use for debugging

* clippy

* Add print IR and print comments options

Tested with `cargo run --bin ruff_python_formatter -- --print-ir --print-comments scratch.py`
2023-06-05 07:33:33 +00:00