Format import statements (#5493)

## Summary

Format import statements in all their variants. Specifically, this
implemented formatting `StmtImport`, `StmtImportFrom` and `Alias`.

## Test Plan

I added some custom snapshots, even though this has been covered well by
black's tests.
This commit is contained in:
konsti 2023-07-04 09:07:20 +02:00 committed by GitHub
parent 6acc316d19
commit 787e2fd49d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
26 changed files with 304 additions and 991 deletions

View file

@ -0,0 +1,3 @@
from a import aksjdhflsakhdflkjsadlfajkslhfdkjsaldajlahflashdfljahlfksajlhfajfjfsaahflakjslhdfkjalhdskjfa
from a import aksjdhflsakhdflkjsadlfajkslhfdkjsaldajlahflashdfljahlfksajlhfajfjfsaahflakjslhdfkjalhdskjfa, aksjdhflsakhdflkjsadlfajkslhfdkjsaldajlahflashdfljahlfksajlhfajfjfsaahflakjslhdfkjalhdskjfa
from a import aksjdhflsakhdflkjsadlfajkslhfdkjsaldajlahflashdfljahlfksajlhfajfjfsaahflakjslhdfkjalhdskjfa as dfgsdfgsd, aksjdhflsakhdflkjsadlfajkslhfdkjsaldajlahflashdfljahlfksajlhfajfjfsaahflakjslhdfkjalhdskjfa as sdkjflsdjlahlfd

View file

@ -0,0 +1,16 @@
from a import aksjdhflsakhdflkjsadlfajkslhf
from a import (
aksjdhflsakhdflkjsadlfajkslhf,
)
from a import (
aksjdhflsakhdflkjsadlfajkslhfdkjsaldajlahflashdfljahlfksajlhfajfjfsaahflakjslhdfkjalhdskjfa,
)
from a import (
aksjdhflsakhdflkjsadlfajkslhfdkjsaldajlahflashdfljahlfksajlhfajfjfsaahflakjslhdfkjalhdskjfa,
aksjdhflsakhdflkjsadlfajkslhfdkjsaldajlahflashdfljahlfksajlhfajfjfsaahflakjslhdfkjalhdskjfa,
)
from a import (
aksjdhflsakhdflkjsadlfajkslhfdkjsaldajlahflashdfljahlfksajlhfajfjfsaahflakjslhdfkjalhdskjfa as dfgsdfgsd,
aksjdhflsakhdflkjsadlfajkslhfdkjsaldajlahflashdfljahlfksajlhfajfjfsaahflakjslhdfkjalhdskjfa as sdkjflsdjlahlfd,
)
from aksjdhflsakhdflkjsadlfajkslhfdkjsaldajlahflashdfljahlfksajlhfajfjfsaahflakjslhdfkjalhdskjfa import *

View file

@ -1,5 +1,6 @@
use crate::{not_yet_implemented, FormatNodeRule, PyFormatter};
use ruff_formatter::{write, Buffer, FormatResult};
use crate::{AsFormat, FormatNodeRule, PyFormatter};
use ruff_formatter::prelude::{space, text};
use ruff_formatter::{write, Buffer, Format, FormatResult};
use rustpython_parser::ast::Alias;
#[derive(Default)]
@ -7,6 +8,15 @@ pub struct FormatAlias;
impl FormatNodeRule<Alias> for FormatAlias {
fn fmt_fields(&self, item: &Alias, f: &mut PyFormatter) -> FormatResult<()> {
write!(f, [not_yet_implemented(item)])
let Alias {
range: _,
name,
asname,
} = item;
name.format().fmt(f)?;
if let Some(asname) = asname {
write!(f, [space(), text("as"), space(), asname.format()])?;
}
Ok(())
}
}

View file

@ -1,4 +1,5 @@
use crate::{not_yet_implemented, FormatNodeRule, PyFormatter};
use crate::{FormatNodeRule, FormattedIterExt, PyFormatter};
use ruff_formatter::prelude::{format_args, format_with, space, text};
use ruff_formatter::{write, Buffer, FormatResult};
use rustpython_parser::ast::StmtImport;
@ -7,6 +8,12 @@ pub struct FormatStmtImport;
impl FormatNodeRule<StmtImport> for FormatStmtImport {
fn fmt_fields(&self, item: &StmtImport, f: &mut PyFormatter) -> FormatResult<()> {
write!(f, [not_yet_implemented(item)])
let StmtImport { names, range: _ } = item;
let names = format_with(|f| {
f.join_with(&format_args![text(","), space()])
.entries(names.iter().formatted())
.finish()
});
write!(f, [text("import"), space(), names])
}
}

View file

@ -1,5 +1,7 @@
use crate::{not_yet_implemented, FormatNodeRule, PyFormatter};
use ruff_formatter::{write, Buffer, FormatResult};
use crate::builders::{optional_parentheses, PyFormatterExtensions};
use crate::{AsFormat, FormatNodeRule, PyFormatter};
use ruff_formatter::prelude::{dynamic_text, format_with, space, text};
use ruff_formatter::{write, Buffer, Format, FormatResult};
use rustpython_parser::ast::StmtImportFrom;
#[derive(Default)]
@ -7,6 +9,40 @@ pub struct FormatStmtImportFrom;
impl FormatNodeRule<StmtImportFrom> for FormatStmtImportFrom {
fn fmt_fields(&self, item: &StmtImportFrom, f: &mut PyFormatter) -> FormatResult<()> {
write!(f, [not_yet_implemented(item)])
let StmtImportFrom {
module,
names,
range: _,
level,
} = item;
let level_str = level
.map(|level| ".".repeat(level.to_usize()))
.unwrap_or(String::default());
write!(
f,
[
text("from"),
space(),
dynamic_text(&level_str, None),
module.as_ref().map(AsFormat::format),
space(),
text("import"),
space(),
]
)?;
if let [name] = names.as_slice() {
// star can't be surrounded by parentheses
if name.name.as_str() == "*" {
return text("*").fmt(f);
}
}
let names = format_with(|f| {
f.join_comma_separated()
.entries(names.iter().map(|name| (name, name.format())))
.finish()
});
optional_parentheses(&names).fmt(f)
}
}

View file

@ -43,21 +43,20 @@ def eggs() -> Union[str, int]: ...
--- Black
+++ Ruff
@@ -1,32 +1,58 @@
-from typing import Union
+NOT_YET_IMPLEMENTED_StmtImportFrom
+
from typing import Union
+
@bird
-def zoo(): ...
+def zoo():
+ ...
+
+
+class A:
+ ...
-class A: ...
+class A:
+ ...
+
+
@bar
class B:
- def BMethod(self) -> None: ...
@ -94,14 +93,14 @@ def eggs() -> Union[str, int]: ...
+
+class F(A, C):
+ ...
+
+
+def spam() -> None:
+ ...
-class F(A, C): ...
-def spam() -> None: ...
+def spam() -> None:
+ ...
+
+
@overload
-def spam(arg: str) -> str: ...
+def spam(arg: str) -> str:
@ -120,7 +119,7 @@ def eggs() -> Union[str, int]: ...
## Ruff Output
```py
NOT_YET_IMPLEMENTED_StmtImportFrom
from typing import Union
@bird

View file

@ -132,8 +132,7 @@ match bar1:
--- Black
+++ Ruff
@@ -1,119 +1,43 @@
-import match
+NOT_YET_IMPLEMENTED_StmtImport
import match
-match something:
- case [a as b]:
@ -208,10 +207,11 @@ match bar1:
- ),
- ):
- pass
-
+NOT_YET_IMPLEMENTED_StmtMatch
- case [a as match]:
- pass
-
- case case:
- pass
+NOT_YET_IMPLEMENTED_StmtMatch
@ -220,8 +220,9 @@ match bar1:
-match match:
- case case:
- pass
-
-
+NOT_YET_IMPLEMENTED_StmtMatch
-match a, *b(), c:
- case d, *f, g:
- pass
@ -236,30 +237,28 @@ match bar1:
- pass
- case {"maybe": something(complicated as this) as that}:
- pass
-
+NOT_YET_IMPLEMENTED_StmtMatch
-match something:
- case 1 as a:
- pass
+NOT_YET_IMPLEMENTED_StmtMatch
- case 2 as b, 3 as c:
- pass
+NOT_YET_IMPLEMENTED_StmtMatch
- case 4 as d, (5 as e), (6 | 7 as g), *h:
- pass
+NOT_YET_IMPLEMENTED_StmtMatch
-
-match bar1:
- case Foo(aa=Callable() as aa, bb=int()):
- print(bar1.aa, bar1.bb)
- case _:
- print("no match", "\n")
+NOT_YET_IMPLEMENTED_StmtMatch
-
-
-match bar1:
- case Foo(
- normal=x, perhaps=[list, {"x": d, "y": 1.0}] as y, otherwise=something, q=t as u
@ -271,7 +270,7 @@ match bar1:
## Ruff Output
```py
NOT_YET_IMPLEMENTED_StmtImport
import match
NOT_YET_IMPLEMENTED_StmtMatch

View file

@ -83,31 +83,9 @@ if True:
```diff
--- Black
+++ Ruff
@@ -1,40 +1,22 @@
-import core, time, a
+NOT_YET_IMPLEMENTED_StmtImport
-from . import A, B, C
+NOT_YET_IMPLEMENTED_StmtImportFrom
# keeps existing trailing comma
-from foo import (
- bar,
-)
+NOT_YET_IMPLEMENTED_StmtImportFrom
# also keeps existing structure
-from foo import (
- baz,
- qux,
-)
+NOT_YET_IMPLEMENTED_StmtImportFrom
# `as` works as well
-from foo import (
- xyzzy as magic,
-)
+NOT_YET_IMPLEMENTED_StmtImportFrom
@@ -18,23 +18,12 @@
xyzzy as magic,
)
-a = {
- 1,
@ -132,7 +110,7 @@ if True:
nested_no_trailing_comma = {(1, 2, 3), (4, 5, 6)}
nested_long_lines = [
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
@@ -52,10 +34,7 @@
@@ -52,10 +41,7 @@
y = {
"oneple": (1,),
}
@ -149,18 +127,25 @@ if True:
## Ruff Output
```py
NOT_YET_IMPLEMENTED_StmtImport
import core, time, a
NOT_YET_IMPLEMENTED_StmtImportFrom
from . import A, B, C
# keeps existing trailing comma
NOT_YET_IMPLEMENTED_StmtImportFrom
from foo import (
bar,
)
# also keeps existing structure
NOT_YET_IMPLEMENTED_StmtImportFrom
from foo import (
baz,
qux,
)
# `as` works as well
NOT_YET_IMPLEMENTED_StmtImportFrom
from foo import (
xyzzy as magic,
)
a = {1, 2, 3}
b = {1, 2, 3}

View file

@ -1,347 +0,0 @@
---
source: crates/ruff_python_formatter/tests/fixtures.rs
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/comments.py
---
## Input
```py
#!/usr/bin/env python3
# fmt: on
# Some license here.
#
# Has many lines. Many, many lines.
# Many, many, many lines.
"""Module docstring.
Possibly also many, many lines.
"""
import os.path
import sys
import a
from b.c import X # some noqa comment
try:
import fast
except ImportError:
import slow as fast
# Some comment before a function.
y = 1
(
# some strings
y # type: ignore
)
def function(default=None):
"""Docstring comes first.
Possibly many lines.
"""
# FIXME: Some comment about why this function is crap but still in production.
import inner_imports
if inner_imports.are_evil():
# Explains why we have this if.
# In great detail indeed.
x = X()
return x.method1() # type: ignore
# This return is also commented for some reason.
return default
# Explains why we use global state.
GLOBAL_STATE = {"a": a(1), "b": a(2), "c": a(3)}
# Another comment!
# This time two lines.
class Foo:
"""Docstring for class Foo. Example from Sphinx docs."""
#: Doc comment for class attribute Foo.bar.
#: It can have multiple lines.
bar = 1
flox = 1.5 #: Doc comment for Foo.flox. One line only.
baz = 2
"""Docstring for class attribute Foo.baz."""
def __init__(self):
#: Doc comment for instance attribute qux.
self.qux = 3
self.spam = 4
"""Docstring for instance attribute spam."""
#' <h1>This is pweave!</h1>
@fast(really=True)
async def wat():
# This comment, for some reason \
# contains a trailing backslash.
async with X.open_async() as x: # Some more comments
result = await x.method1()
# Comment after ending a block.
if result:
print("A OK", file=sys.stdout)
# Comment between things.
print()
# Some closing comments.
# Maybe Vim or Emacs directives for formatting.
# Who knows.
```
## Black Differences
```diff
--- Black
+++ Ruff
@@ -9,16 +9,16 @@
Possibly also many, many lines.
"""
-import os.path
-import sys
+NOT_YET_IMPLEMENTED_StmtImport
+NOT_YET_IMPLEMENTED_StmtImport
-import a
-from b.c import X # some noqa comment
+NOT_YET_IMPLEMENTED_StmtImport
+NOT_YET_IMPLEMENTED_StmtImportFrom # some noqa comment
try:
- import fast
+ NOT_YET_IMPLEMENTED_StmtImport
except ImportError:
- import slow as fast
+ NOT_YET_IMPLEMENTED_StmtImport
# Some comment before a function.
@@ -35,7 +35,7 @@
Possibly many lines.
"""
# FIXME: Some comment about why this function is crap but still in production.
- import inner_imports
+ NOT_YET_IMPLEMENTED_StmtImport
if inner_imports.are_evil():
# Explains why we have this if.
```
## Ruff Output
```py
#!/usr/bin/env python3
# fmt: on
# Some license here.
#
# Has many lines. Many, many lines.
# Many, many, many lines.
"""Module docstring.
Possibly also many, many lines.
"""
NOT_YET_IMPLEMENTED_StmtImport
NOT_YET_IMPLEMENTED_StmtImport
NOT_YET_IMPLEMENTED_StmtImport
NOT_YET_IMPLEMENTED_StmtImportFrom # some noqa comment
try:
NOT_YET_IMPLEMENTED_StmtImport
except ImportError:
NOT_YET_IMPLEMENTED_StmtImport
# Some comment before a function.
y = 1
(
# some strings
y # type: ignore
)
def function(default=None):
"""Docstring comes first.
Possibly many lines.
"""
# FIXME: Some comment about why this function is crap but still in production.
NOT_YET_IMPLEMENTED_StmtImport
if inner_imports.are_evil():
# Explains why we have this if.
# In great detail indeed.
x = X()
return x.method1() # type: ignore
# This return is also commented for some reason.
return default
# Explains why we use global state.
GLOBAL_STATE = {"a": a(1), "b": a(2), "c": a(3)}
# Another comment!
# This time two lines.
class Foo:
"""Docstring for class Foo. Example from Sphinx docs."""
#: Doc comment for class attribute Foo.bar.
#: It can have multiple lines.
bar = 1
flox = 1.5 #: Doc comment for Foo.flox. One line only.
baz = 2
"""Docstring for class attribute Foo.baz."""
def __init__(self):
#: Doc comment for instance attribute qux.
self.qux = 3
self.spam = 4
"""Docstring for instance attribute spam."""
#' <h1>This is pweave!</h1>
@fast(really=True)
async def wat():
# This comment, for some reason \
# contains a trailing backslash.
async with X.open_async() as x: # Some more comments
result = await x.method1()
# Comment after ending a block.
if result:
print("A OK", file=sys.stdout)
# Comment between things.
print()
# Some closing comments.
# Maybe Vim or Emacs directives for formatting.
# Who knows.
```
## Black Output
```py
#!/usr/bin/env python3
# fmt: on
# Some license here.
#
# Has many lines. Many, many lines.
# Many, many, many lines.
"""Module docstring.
Possibly also many, many lines.
"""
import os.path
import sys
import a
from b.c import X # some noqa comment
try:
import fast
except ImportError:
import slow as fast
# Some comment before a function.
y = 1
(
# some strings
y # type: ignore
)
def function(default=None):
"""Docstring comes first.
Possibly many lines.
"""
# FIXME: Some comment about why this function is crap but still in production.
import inner_imports
if inner_imports.are_evil():
# Explains why we have this if.
# In great detail indeed.
x = X()
return x.method1() # type: ignore
# This return is also commented for some reason.
return default
# Explains why we use global state.
GLOBAL_STATE = {"a": a(1), "b": a(2), "c": a(3)}
# Another comment!
# This time two lines.
class Foo:
"""Docstring for class Foo. Example from Sphinx docs."""
#: Doc comment for class attribute Foo.bar.
#: It can have multiple lines.
bar = 1
flox = 1.5 #: Doc comment for Foo.flox. One line only.
baz = 2
"""Docstring for class attribute Foo.baz."""
def __init__(self):
#: Doc comment for instance attribute qux.
self.qux = 3
self.spam = 4
"""Docstring for instance attribute spam."""
#' <h1>This is pweave!</h1>
@fast(really=True)
async def wat():
# This comment, for some reason \
# contains a trailing backslash.
async with X.open_async() as x: # Some more comments
result = await x.method1()
# Comment after ending a block.
if result:
print("A OK", file=sys.stdout)
# Comment between things.
print()
# Some closing comments.
# Maybe Vim or Emacs directives for formatting.
# Who knows.
```

View file

@ -177,19 +177,18 @@ instruction()#comment with bad spacing
```diff
--- Black
+++ Ruff
@@ -1,9 +1,5 @@
-from com.my_lovely_company.my_lovely_team.my_lovely_project.my_lovely_component import (
@@ -1,8 +1,8 @@
from com.my_lovely_company.my_lovely_team.my_lovely_project.my_lovely_component import (
- MyLovelyCompanyTeamProjectComponent, # NOT DRY
-)
-from com.my_lovely_company.my_lovely_team.my_lovely_project.my_lovely_component import (
+ MyLovelyCompanyTeamProjectComponent # NOT DRY
)
from com.my_lovely_company.my_lovely_team.my_lovely_project.my_lovely_component import (
- MyLovelyCompanyTeamProjectComponent as component, # DRY
-)
+NOT_YET_IMPLEMENTED_StmtImportFrom
+NOT_YET_IMPLEMENTED_StmtImportFrom
+ MyLovelyCompanyTeamProjectComponent as component # DRY
)
# Please keep __all__ alphabetized within each category.
@@ -45,7 +41,7 @@
@@ -45,7 +45,7 @@
# user-defined types and objects
Cheese,
Cheese("Wensleydale"),
@ -198,7 +197,7 @@ instruction()#comment with bad spacing
]
if "PYTHON" in os.environ:
@@ -60,8 +56,12 @@
@@ -60,8 +60,12 @@
# Comment before function.
def inline_comments_in_brackets_ruin_everything():
if typedargslist:
@ -212,7 +211,7 @@ instruction()#comment with bad spacing
children[0],
body,
children[-1], # type: ignore
@@ -72,7 +72,11 @@
@@ -72,7 +76,11 @@
body,
parameters.children[-1], # )2
]
@ -225,7 +224,7 @@ instruction()#comment with bad spacing
if (
self._proc is not None
# has the child process finished?
@@ -114,25 +118,9 @@
@@ -114,25 +122,9 @@
# yup
arg3=True,
)
@ -254,7 +253,7 @@ instruction()#comment with bad spacing
while True:
if False:
continue
@@ -143,7 +131,10 @@
@@ -143,7 +135,10 @@
# let's return
return Node(
syms.simple_stmt,
@ -266,7 +265,7 @@ instruction()#comment with bad spacing
)
@@ -158,7 +149,11 @@
@@ -158,7 +153,11 @@
class Test:
def _init_host(self, parsed) -> None:
@ -284,8 +283,12 @@ instruction()#comment with bad spacing
## Ruff Output
```py
NOT_YET_IMPLEMENTED_StmtImportFrom
NOT_YET_IMPLEMENTED_StmtImportFrom
from com.my_lovely_company.my_lovely_team.my_lovely_project.my_lovely_component import (
MyLovelyCompanyTeamProjectComponent # NOT DRY
)
from com.my_lovely_company.my_lovely_team.my_lovely_project.my_lovely_component import (
MyLovelyCompanyTeamProjectComponent as component # DRY
)
# Please keep __all__ alphabetized within each category.

View file

@ -106,19 +106,7 @@ def foo3(list_a, list_b):
```diff
--- Black
+++ Ruff
@@ -1,9 +1,5 @@
-from com.my_lovely_company.my_lovely_team.my_lovely_project.my_lovely_component import (
- MyLovelyCompanyTeamProjectComponent, # NOT DRY
-)
-from com.my_lovely_company.my_lovely_team.my_lovely_project.my_lovely_component import (
- MyLovelyCompanyTeamProjectComponent as component, # DRY
-)
+NOT_YET_IMPLEMENTED_StmtImportFrom
+NOT_YET_IMPLEMENTED_StmtImportFrom
class C:
@@ -58,37 +54,28 @@
@@ -58,37 +58,28 @@
def foo(list_a, list_b):
results = (
@ -172,8 +160,12 @@ def foo3(list_a, list_b):
## Ruff Output
```py
NOT_YET_IMPLEMENTED_StmtImportFrom
NOT_YET_IMPLEMENTED_StmtImportFrom
from com.my_lovely_company.my_lovely_team.my_lovely_project.my_lovely_component import (
MyLovelyCompanyTeamProjectComponent, # NOT DRY
)
from com.my_lovely_company.my_lovely_team.my_lovely_project.my_lovely_component import (
MyLovelyCompanyTeamProjectComponent as component, # DRY
)
class C:

View file

@ -1,255 +0,0 @@
---
source: crates/ruff_python_formatter/tests/fixtures.rs
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/comments5.py
---
## Input
```py
while True:
if something.changed:
do.stuff() # trailing comment
# Comment belongs to the `if` block.
# This one belongs to the `while` block.
# Should this one, too? I guess so.
# This one is properly standalone now.
for i in range(100):
# first we do this
if i % 33 == 0:
break
# then we do this
print(i)
# and finally we loop around
with open(some_temp_file) as f:
data = f.read()
try:
with open(some_other_file) as w:
w.write(data)
except OSError:
print("problems")
import sys
# leading function comment
def wat():
...
# trailing function comment
# SECTION COMMENT
# leading 1
@deco1
# leading 2
@deco2(with_args=True)
# leading 3
@deco3
def decorated1():
...
# leading 1
@deco1
# leading 2
@deco2(with_args=True)
# leading function comment
def decorated1():
...
# Note: this is fixed in
# Preview.empty_lines_before_class_or_def_with_leading_comments.
# In the current style, the user will have to split those lines by hand.
some_instruction
# This comment should be split from `some_instruction` by two lines but isn't.
def g():
...
if __name__ == "__main__":
main()
```
## Black Differences
```diff
--- Black
+++ Ruff
@@ -27,7 +27,7 @@
except OSError:
print("problems")
-import sys
+NOT_YET_IMPLEMENTED_StmtImport
# leading function comment
```
## Ruff Output
```py
while True:
if something.changed:
do.stuff() # trailing comment
# Comment belongs to the `if` block.
# This one belongs to the `while` block.
# Should this one, too? I guess so.
# This one is properly standalone now.
for i in range(100):
# first we do this
if i % 33 == 0:
break
# then we do this
print(i)
# and finally we loop around
with open(some_temp_file) as f:
data = f.read()
try:
with open(some_other_file) as w:
w.write(data)
except OSError:
print("problems")
NOT_YET_IMPLEMENTED_StmtImport
# leading function comment
def wat():
...
# trailing function comment
# SECTION COMMENT
# leading 1
@deco1
# leading 2
@deco2(with_args=True)
# leading 3
@deco3
def decorated1():
...
# leading 1
@deco1
# leading 2
@deco2(with_args=True)
# leading function comment
def decorated1():
...
# Note: this is fixed in
# Preview.empty_lines_before_class_or_def_with_leading_comments.
# In the current style, the user will have to split those lines by hand.
some_instruction
# This comment should be split from `some_instruction` by two lines but isn't.
def g():
...
if __name__ == "__main__":
main()
```
## Black Output
```py
while True:
if something.changed:
do.stuff() # trailing comment
# Comment belongs to the `if` block.
# This one belongs to the `while` block.
# Should this one, too? I guess so.
# This one is properly standalone now.
for i in range(100):
# first we do this
if i % 33 == 0:
break
# then we do this
print(i)
# and finally we loop around
with open(some_temp_file) as f:
data = f.read()
try:
with open(some_other_file) as w:
w.write(data)
except OSError:
print("problems")
import sys
# leading function comment
def wat():
...
# trailing function comment
# SECTION COMMENT
# leading 1
@deco1
# leading 2
@deco2(with_args=True)
# leading 3
@deco3
def decorated1():
...
# leading 1
@deco1
# leading 2
@deco2(with_args=True)
# leading function comment
def decorated1():
...
# Note: this is fixed in
# Preview.empty_lines_before_class_or_def_with_leading_comments.
# In the current style, the user will have to split those lines by hand.
some_instruction
# This comment should be split from `some_instruction` by two lines but isn't.
def g():
...
if __name__ == "__main__":
main()
```

View file

@ -130,12 +130,6 @@ aaaaaaaaaaaaa, bbbbbbbbb = map(list, map(itertools.chain.from_iterable, zip(*ite
```diff
--- Black
+++ Ruff
@@ -1,4 +1,4 @@
-from typing import Any, Tuple
+NOT_YET_IMPLEMENTED_StmtImportFrom
def f(
@@ -49,9 +49,7 @@
element = 0 # type: int
another_element = 1 # type: float
@ -192,7 +186,7 @@ aaaaaaaaaaaaa, bbbbbbbbb = map(list, map(itertools.chain.from_iterable, zip(*ite
## Ruff Output
```py
NOT_YET_IMPLEMENTED_StmtImportFrom
from typing import Any, Tuple
def f(

View file

@ -31,18 +31,7 @@ def function(a:int=42):
```diff
--- Black
+++ Ruff
@@ -1,9 +1,4 @@
-from .config import (
- ConfigTypeAttributes,
- Int,
- Path, # String,
- # DEFAULT_TYPE_ATTRIBUTES,
-)
+NOT_YET_IMPLEMENTED_StmtImportFrom
result = 1 # A simple comment
result = (1,) # Another one
@@ -14,9 +9,9 @@
@@ -14,9 +14,9 @@
def function(a: int = 42):
@ -60,7 +49,12 @@ def function(a:int=42):
## Ruff Output
```py
NOT_YET_IMPLEMENTED_StmtImportFrom
from .config import (
ConfigTypeAttributes,
Int,
Path, # String,
# DEFAULT_TYPE_ATTRIBUTES,
)
result = 1 # A simple comment
result = (1,) # Another one

View file

@ -198,22 +198,13 @@ d={'a':1,
```diff
--- Black
+++ Ruff
@@ -1,15 +1,14 @@
#!/usr/bin/env python3
-import asyncio
-import sys
+NOT_YET_IMPLEMENTED_StmtImport
+NOT_YET_IMPLEMENTED_StmtImport
@@ -6,10 +6,9 @@
-from third_party import X, Y, Z
+NOT_YET_IMPLEMENTED_StmtImportFrom
-from library import some_connection, some_decorator
+NOT_YET_IMPLEMENTED_StmtImportFrom
from library import some_connection, some_decorator
# fmt: off
-from third_party import (X,
- Y, Z)
+NOT_YET_IMPLEMENTED_StmtImportFrom
+from third_party import X, Y, Z
# fmt: on
-f"trigger 3.6 mode"
+NOT_YET_IMPLEMENTED_ExprJoinedStr
@ -336,7 +327,7 @@ d={'a':1,
# fmt: off
- from hello import a, b
- 'unformatted'
+ NOT_YET_IMPLEMENTED_StmtImportFrom
+ from hello import a, b
+ "unformatted"
# fmt: on
@ -433,14 +424,14 @@ d={'a':1,
```py
#!/usr/bin/env python3
NOT_YET_IMPLEMENTED_StmtImport
NOT_YET_IMPLEMENTED_StmtImport
import asyncio
import sys
NOT_YET_IMPLEMENTED_StmtImportFrom
from third_party import X, Y, Z
NOT_YET_IMPLEMENTED_StmtImportFrom
from library import some_connection, some_decorator
# fmt: off
NOT_YET_IMPLEMENTED_StmtImportFrom
from third_party import X, Y, Z
# fmt: on
NOT_YET_IMPLEMENTED_ExprJoinedStr
# Comment 1
@ -539,7 +530,7 @@ def subscriptlist():
def import_as_names():
# fmt: off
NOT_YET_IMPLEMENTED_StmtImportFrom
from hello import a, b
"unformatted"
# fmt: on

View file

@ -52,12 +52,7 @@ def test_calculate_fades():
```diff
--- Black
+++ Ruff
@@ -1,40 +1,44 @@
-import pytest
+NOT_YET_IMPLEMENTED_StmtImport
TmSt = 1
TmEx = 2
@@ -5,36 +5,40 @@
# fmt: off
@ -113,7 +108,7 @@ def test_calculate_fades():
## Ruff Output
```py
NOT_YET_IMPLEMENTED_StmtImport
import pytest
TmSt = 1
TmEx = 2

View file

@ -1,114 +0,0 @@
---
source: crates/ruff_python_formatter/tests/fixtures.rs
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/fmtpass_imports.py
---
## Input
```py
# Regression test for https://github.com/psf/black/issues/3438
import ast
import collections # fmt: skip
import dataclasses
# fmt: off
import os
# fmt: on
import pathlib
import re # fmt: skip
import secrets
# fmt: off
import sys
# fmt: on
import tempfile
import zoneinfo
```
## Black Differences
```diff
--- Black
+++ Ruff
@@ -1,19 +1,19 @@
# Regression test for https://github.com/psf/black/issues/3438
-import ast
-import collections # fmt: skip
-import dataclasses
+NOT_YET_IMPLEMENTED_StmtImport
+NOT_YET_IMPLEMENTED_StmtImport # fmt: skip
+NOT_YET_IMPLEMENTED_StmtImport
# fmt: off
-import os
+NOT_YET_IMPLEMENTED_StmtImport
# fmt: on
-import pathlib
+NOT_YET_IMPLEMENTED_StmtImport
-import re # fmt: skip
-import secrets
+NOT_YET_IMPLEMENTED_StmtImport # fmt: skip
+NOT_YET_IMPLEMENTED_StmtImport
# fmt: off
-import sys
+NOT_YET_IMPLEMENTED_StmtImport
# fmt: on
-import tempfile
-import zoneinfo
+NOT_YET_IMPLEMENTED_StmtImport
+NOT_YET_IMPLEMENTED_StmtImport
```
## Ruff Output
```py
# Regression test for https://github.com/psf/black/issues/3438
NOT_YET_IMPLEMENTED_StmtImport
NOT_YET_IMPLEMENTED_StmtImport # fmt: skip
NOT_YET_IMPLEMENTED_StmtImport
# fmt: off
NOT_YET_IMPLEMENTED_StmtImport
# fmt: on
NOT_YET_IMPLEMENTED_StmtImport
NOT_YET_IMPLEMENTED_StmtImport # fmt: skip
NOT_YET_IMPLEMENTED_StmtImport
# fmt: off
NOT_YET_IMPLEMENTED_StmtImport
# fmt: on
NOT_YET_IMPLEMENTED_StmtImport
NOT_YET_IMPLEMENTED_StmtImport
```
## Black Output
```py
# Regression test for https://github.com/psf/black/issues/3438
import ast
import collections # fmt: skip
import dataclasses
# fmt: off
import os
# fmt: on
import pathlib
import re # fmt: skip
import secrets
# fmt: off
import sys
# fmt: on
import tempfile
import zoneinfo
```

View file

@ -107,20 +107,12 @@ def __await__(): return (yield)
```diff
--- Black
+++ Ruff
@@ -1,12 +1,11 @@
#!/usr/bin/env python3
-import asyncio
-import sys
+NOT_YET_IMPLEMENTED_StmtImport
+NOT_YET_IMPLEMENTED_StmtImport
@@ -5,8 +5,7 @@
from third_party import X, Y, Z
-from third_party import X, Y, Z
+NOT_YET_IMPLEMENTED_StmtImportFrom
-from library import some_connection, some_decorator
from library import some_connection, some_decorator
-
-f"trigger 3.6 mode"
+NOT_YET_IMPLEMENTED_StmtImportFrom
+NOT_YET_IMPLEMENTED_ExprJoinedStr
@ -221,12 +213,12 @@ def __await__(): return (yield)
```py
#!/usr/bin/env python3
NOT_YET_IMPLEMENTED_StmtImport
NOT_YET_IMPLEMENTED_StmtImport
import asyncio
import sys
NOT_YET_IMPLEMENTED_StmtImportFrom
from third_party import X, Y, Z
NOT_YET_IMPLEMENTED_StmtImportFrom
from library import some_connection, some_decorator
NOT_YET_IMPLEMENTED_ExprJoinedStr

View file

@ -65,22 +65,15 @@ with hmm_but_this_should_get_two_preceding_newlines():
```diff
--- Black
+++ Ruff
@@ -32,34 +32,28 @@
if os.name == "posix":
- import termios
+ NOT_YET_IMPLEMENTED_StmtImport
@@ -36,7 +36,6 @@
def i_should_be_followed_by_only_one_newline():
pass
-
elif os.name == "nt":
try:
- import msvcrt
+ NOT_YET_IMPLEMENTED_StmtImport
def i_should_be_followed_by_only_one_newline():
import msvcrt
@@ -45,21 +44,16 @@
pass
except ImportError:
@ -141,13 +134,13 @@ def h():
if os.name == "posix":
NOT_YET_IMPLEMENTED_StmtImport
import termios
def i_should_be_followed_by_only_one_newline():
pass
elif os.name == "nt":
try:
NOT_YET_IMPLEMENTED_StmtImport
import msvcrt
def i_should_be_followed_by_only_one_newline():
pass

View file

@ -61,79 +61,15 @@ __all__ = (
```diff
--- Black
+++ Ruff
@@ -2,53 +2,31 @@
# flake8: noqa
-from logging import WARNING
-from logging import (
- ERROR,
-)
-import sys
+NOT_YET_IMPLEMENTED_StmtImportFrom
+NOT_YET_IMPLEMENTED_StmtImportFrom
+NOT_YET_IMPLEMENTED_StmtImport
# This relies on each of the submodules having an __all__ variable.
-from .base_events import *
-from .coroutines import *
-from .events import * # comment here
+NOT_YET_IMPLEMENTED_StmtImportFrom
+NOT_YET_IMPLEMENTED_StmtImportFrom
+NOT_YET_IMPLEMENTED_StmtImportFrom # comment here
-from .futures import *
-from .locks import * # comment here
-from .protocols import *
+NOT_YET_IMPLEMENTED_StmtImportFrom
+NOT_YET_IMPLEMENTED_StmtImportFrom # comment here
+NOT_YET_IMPLEMENTED_StmtImportFrom
-from ..runners import * # comment here
-from ..queues import *
-from ..streams import *
+NOT_YET_IMPLEMENTED_StmtImportFrom # comment here
+NOT_YET_IMPLEMENTED_StmtImportFrom
+NOT_YET_IMPLEMENTED_StmtImportFrom
-from some_library import (
- Just,
- Enough,
- Libraries,
- To,
- Fit,
- In,
- This,
- Nice,
- Split,
- Which,
- We,
- No,
- Longer,
- Use,
-)
-from name_of_a_company.extremely_long_project_name.component.ttypes import (
@@ -38,7 +38,7 @@
Use,
)
from name_of_a_company.extremely_long_project_name.component.ttypes import (
- CuteLittleServiceHandlerFactoryyy,
-)
-from name_of_a_company.extremely_long_project_name.extremely_long_component_name.ttypes import *
+NOT_YET_IMPLEMENTED_StmtImportFrom
+NOT_YET_IMPLEMENTED_StmtImportFrom
+NOT_YET_IMPLEMENTED_StmtImportFrom
+ CuteLittleServiceHandlerFactoryyy
)
from name_of_a_company.extremely_long_project_name.extremely_long_component_name.ttypes import *
-from .a.b.c.subprocess import *
-from . import tasks
-from . import A, B, C
-from . import (
- SomeVeryLongNameAndAllOfItsAdditionalLetters1,
- SomeVeryLongNameAndAllOfItsAdditionalLetters2,
-)
+NOT_YET_IMPLEMENTED_StmtImportFrom
+NOT_YET_IMPLEMENTED_StmtImportFrom
+NOT_YET_IMPLEMENTED_StmtImportFrom
+NOT_YET_IMPLEMENTED_StmtImportFrom
__all__ = (
base_events.__all__
```
## Ruff Output
@ -143,31 +79,53 @@ __all__ = (
# flake8: noqa
NOT_YET_IMPLEMENTED_StmtImportFrom
NOT_YET_IMPLEMENTED_StmtImportFrom
NOT_YET_IMPLEMENTED_StmtImport
from logging import WARNING
from logging import (
ERROR,
)
import sys
# This relies on each of the submodules having an __all__ variable.
NOT_YET_IMPLEMENTED_StmtImportFrom
NOT_YET_IMPLEMENTED_StmtImportFrom
NOT_YET_IMPLEMENTED_StmtImportFrom # comment here
from .base_events import *
from .coroutines import *
from .events import * # comment here
NOT_YET_IMPLEMENTED_StmtImportFrom
NOT_YET_IMPLEMENTED_StmtImportFrom # comment here
NOT_YET_IMPLEMENTED_StmtImportFrom
from .futures import *
from .locks import * # comment here
from .protocols import *
NOT_YET_IMPLEMENTED_StmtImportFrom # comment here
NOT_YET_IMPLEMENTED_StmtImportFrom
NOT_YET_IMPLEMENTED_StmtImportFrom
from ..runners import * # comment here
from ..queues import *
from ..streams import *
NOT_YET_IMPLEMENTED_StmtImportFrom
NOT_YET_IMPLEMENTED_StmtImportFrom
NOT_YET_IMPLEMENTED_StmtImportFrom
from some_library import (
Just,
Enough,
Libraries,
To,
Fit,
In,
This,
Nice,
Split,
Which,
We,
No,
Longer,
Use,
)
from name_of_a_company.extremely_long_project_name.component.ttypes import (
CuteLittleServiceHandlerFactoryyy
)
from name_of_a_company.extremely_long_project_name.extremely_long_component_name.ttypes import *
NOT_YET_IMPLEMENTED_StmtImportFrom
NOT_YET_IMPLEMENTED_StmtImportFrom
NOT_YET_IMPLEMENTED_StmtImportFrom
NOT_YET_IMPLEMENTED_StmtImportFrom
from .a.b.c.subprocess import *
from . import tasks
from . import A, B, C
from . import (
SomeVeryLongNameAndAllOfItsAdditionalLetters1,
SomeVeryLongNameAndAllOfItsAdditionalLetters2,
)
__all__ = (
base_events.__all__

View file

@ -93,12 +93,6 @@ async def main():
```diff
--- Black
+++ Ruff
@@ -1,4 +1,4 @@
-import asyncio
+NOT_YET_IMPLEMENTED_StmtImport
# Control example
@@ -8,59 +8,70 @@
# Remove brackets for short coroutine/task
@ -219,7 +213,7 @@ async def main():
## Ruff Output
```py
NOT_YET_IMPLEMENTED_StmtImport
import asyncio
# Control example

View file

@ -120,12 +120,6 @@ with open("/path/to/file.txt", mode="r") as read_file:
```diff
--- Black
+++ Ruff
@@ -1,4 +1,4 @@
-import random
+NOT_YET_IMPLEMENTED_StmtImport
def foo1():
@@ -27,16 +27,16 @@
@ -151,7 +145,7 @@ with open("/path/to/file.txt", mode="r") as read_file:
## Ruff Output
```py
NOT_YET_IMPLEMENTED_StmtImport
import random
def foo1():

View file

@ -111,7 +111,7 @@ x53 = (
## Output
```py
NOT_YET_IMPLEMENTED_StmtImportFrom
from argparse import Namespace
a = Namespace()

View file

@ -96,7 +96,7 @@ f(
## Output
```py
NOT_YET_IMPLEMENTED_StmtImportFrom
from unittest.mock import MagicMock
def f(*args, **kwargs):

View file

@ -0,0 +1,28 @@
---
source: crates/ruff_python_formatter/tests/fixtures.rs
input_file: crates/ruff_python_formatter/resources/test/fixtures/ruff/statement/import.py
---
## Input
```py
from a import aksjdhflsakhdflkjsadlfajkslhfdkjsaldajlahflashdfljahlfksajlhfajfjfsaahflakjslhdfkjalhdskjfa
from a import aksjdhflsakhdflkjsadlfajkslhfdkjsaldajlahflashdfljahlfksajlhfajfjfsaahflakjslhdfkjalhdskjfa, aksjdhflsakhdflkjsadlfajkslhfdkjsaldajlahflashdfljahlfksajlhfajfjfsaahflakjslhdfkjalhdskjfa
from a import aksjdhflsakhdflkjsadlfajkslhfdkjsaldajlahflashdfljahlfksajlhfajfjfsaahflakjslhdfkjalhdskjfa as dfgsdfgsd, aksjdhflsakhdflkjsadlfajkslhfdkjsaldajlahflashdfljahlfksajlhfajfjfsaahflakjslhdfkjalhdskjfa as sdkjflsdjlahlfd
```
## Output
```py
from a import (
aksjdhflsakhdflkjsadlfajkslhfdkjsaldajlahflashdfljahlfksajlhfajfjfsaahflakjslhdfkjalhdskjfa
)
from a import (
aksjdhflsakhdflkjsadlfajkslhfdkjsaldajlahflashdfljahlfksajlhfajfjfsaahflakjslhdfkjalhdskjfa,
aksjdhflsakhdflkjsadlfajkslhfdkjsaldajlahflashdfljahlfksajlhfajfjfsaahflakjslhdfkjalhdskjfa,
)
from a import (
aksjdhflsakhdflkjsadlfajkslhfdkjsaldajlahflashdfljahlfksajlhfajfjfsaahflakjslhdfkjalhdskjfa as dfgsdfgsd,
aksjdhflsakhdflkjsadlfajkslhfdkjsaldajlahflashdfljahlfksajlhfajfjfsaahflakjslhdfkjalhdskjfa as sdkjflsdjlahlfd,
)
```

View file

@ -0,0 +1,46 @@
---
source: crates/ruff_python_formatter/tests/fixtures.rs
input_file: crates/ruff_python_formatter/resources/test/fixtures/ruff/statement/import_from.py
---
## Input
```py
from a import aksjdhflsakhdflkjsadlfajkslhf
from a import (
aksjdhflsakhdflkjsadlfajkslhf,
)
from a import (
aksjdhflsakhdflkjsadlfajkslhfdkjsaldajlahflashdfljahlfksajlhfajfjfsaahflakjslhdfkjalhdskjfa,
)
from a import (
aksjdhflsakhdflkjsadlfajkslhfdkjsaldajlahflashdfljahlfksajlhfajfjfsaahflakjslhdfkjalhdskjfa,
aksjdhflsakhdflkjsadlfajkslhfdkjsaldajlahflashdfljahlfksajlhfajfjfsaahflakjslhdfkjalhdskjfa,
)
from a import (
aksjdhflsakhdflkjsadlfajkslhfdkjsaldajlahflashdfljahlfksajlhfajfjfsaahflakjslhdfkjalhdskjfa as dfgsdfgsd,
aksjdhflsakhdflkjsadlfajkslhfdkjsaldajlahflashdfljahlfksajlhfajfjfsaahflakjslhdfkjalhdskjfa as sdkjflsdjlahlfd,
)
from aksjdhflsakhdflkjsadlfajkslhfdkjsaldajlahflashdfljahlfksajlhfajfjfsaahflakjslhdfkjalhdskjfa import *
```
## Output
```py
from a import aksjdhflsakhdflkjsadlfajkslhf
from a import (
aksjdhflsakhdflkjsadlfajkslhf,
)
from a import (
aksjdhflsakhdflkjsadlfajkslhfdkjsaldajlahflashdfljahlfksajlhfajfjfsaahflakjslhdfkjalhdskjfa,
)
from a import (
aksjdhflsakhdflkjsadlfajkslhfdkjsaldajlahflashdfljahlfksajlhfajfjfsaahflakjslhdfkjalhdskjfa,
aksjdhflsakhdflkjsadlfajkslhfdkjsaldajlahflashdfljahlfksajlhfajfjfsaahflakjslhdfkjalhdskjfa,
)
from a import (
aksjdhflsakhdflkjsadlfajkslhfdkjsaldajlahflashdfljahlfksajlhfajfjfsaahflakjslhdfkjalhdskjfa as dfgsdfgsd,
aksjdhflsakhdflkjsadlfajkslhfdkjsaldajlahflashdfljahlfksajlhfajfjfsaahflakjslhdfkjalhdskjfa as sdkjflsdjlahlfd,
)
from aksjdhflsakhdflkjsadlfajkslhfdkjsaldajlahflashdfljahlfksajlhfajfjfsaahflakjslhdfkjalhdskjfa import *
```