Format `class` definitions (#5289)

This commit is contained in:
Micha Reiser 2023-06-22 11:09:43 +02:00 committed by GitHub
parent 7d4f8e59da
commit f7e1cf4b51
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
27 changed files with 914 additions and 541 deletions

12
Cargo.lock generated
View File

@ -2105,7 +2105,7 @@ dependencies = [
[[package]] [[package]]
name = "ruff_text_size" name = "ruff_text_size"
version = "0.0.0" version = "0.0.0"
source = "git+https://github.com/astral-sh/RustPython-Parser.git?rev=08ebbe40d7776cac6e3ba66277d435056f2b8dca#08ebbe40d7776cac6e3ba66277d435056f2b8dca" source = "git+https://github.com/astral-sh/RustPython-Parser.git?rev=f60e204b73b95bdb6ce87ccd0de34081b4a17c11#f60e204b73b95bdb6ce87ccd0de34081b4a17c11"
dependencies = [ dependencies = [
"schemars", "schemars",
"serde", "serde",
@ -2183,7 +2183,7 @@ dependencies = [
[[package]] [[package]]
name = "rustpython-ast" name = "rustpython-ast"
version = "0.2.0" version = "0.2.0"
source = "git+https://github.com/astral-sh/RustPython-Parser.git?rev=08ebbe40d7776cac6e3ba66277d435056f2b8dca#08ebbe40d7776cac6e3ba66277d435056f2b8dca" source = "git+https://github.com/astral-sh/RustPython-Parser.git?rev=f60e204b73b95bdb6ce87ccd0de34081b4a17c11#f60e204b73b95bdb6ce87ccd0de34081b4a17c11"
dependencies = [ dependencies = [
"is-macro", "is-macro",
"num-bigint", "num-bigint",
@ -2194,7 +2194,7 @@ dependencies = [
[[package]] [[package]]
name = "rustpython-format" name = "rustpython-format"
version = "0.2.0" version = "0.2.0"
source = "git+https://github.com/astral-sh/RustPython-Parser.git?rev=08ebbe40d7776cac6e3ba66277d435056f2b8dca#08ebbe40d7776cac6e3ba66277d435056f2b8dca" source = "git+https://github.com/astral-sh/RustPython-Parser.git?rev=f60e204b73b95bdb6ce87ccd0de34081b4a17c11#f60e204b73b95bdb6ce87ccd0de34081b4a17c11"
dependencies = [ dependencies = [
"bitflags 2.3.1", "bitflags 2.3.1",
"itertools", "itertools",
@ -2206,7 +2206,7 @@ dependencies = [
[[package]] [[package]]
name = "rustpython-literal" name = "rustpython-literal"
version = "0.2.0" version = "0.2.0"
source = "git+https://github.com/astral-sh/RustPython-Parser.git?rev=08ebbe40d7776cac6e3ba66277d435056f2b8dca#08ebbe40d7776cac6e3ba66277d435056f2b8dca" source = "git+https://github.com/astral-sh/RustPython-Parser.git?rev=f60e204b73b95bdb6ce87ccd0de34081b4a17c11#f60e204b73b95bdb6ce87ccd0de34081b4a17c11"
dependencies = [ dependencies = [
"hexf-parse", "hexf-parse",
"is-macro", "is-macro",
@ -2218,7 +2218,7 @@ dependencies = [
[[package]] [[package]]
name = "rustpython-parser" name = "rustpython-parser"
version = "0.2.0" version = "0.2.0"
source = "git+https://github.com/astral-sh/RustPython-Parser.git?rev=08ebbe40d7776cac6e3ba66277d435056f2b8dca#08ebbe40d7776cac6e3ba66277d435056f2b8dca" source = "git+https://github.com/astral-sh/RustPython-Parser.git?rev=f60e204b73b95bdb6ce87ccd0de34081b4a17c11#f60e204b73b95bdb6ce87ccd0de34081b4a17c11"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"is-macro", "is-macro",
@ -2241,7 +2241,7 @@ dependencies = [
[[package]] [[package]]
name = "rustpython-parser-core" name = "rustpython-parser-core"
version = "0.2.0" version = "0.2.0"
source = "git+https://github.com/astral-sh/RustPython-Parser.git?rev=08ebbe40d7776cac6e3ba66277d435056f2b8dca#08ebbe40d7776cac6e3ba66277d435056f2b8dca" source = "git+https://github.com/astral-sh/RustPython-Parser.git?rev=f60e204b73b95bdb6ce87ccd0de34081b4a17c11#f60e204b73b95bdb6ce87ccd0de34081b4a17c11"
dependencies = [ dependencies = [
"is-macro", "is-macro",
"memchr", "memchr",

View File

@ -50,15 +50,15 @@ toml = { version = "0.7.2" }
# v0.0.1 # v0.0.1
libcst = { git = "https://github.com/charliermarsh/LibCST", rev = "80e4c1399f95e5beb532fdd1e209ad2dbb470438" } libcst = { git = "https://github.com/charliermarsh/LibCST", rev = "80e4c1399f95e5beb532fdd1e209ad2dbb470438" }
# v0.0.3 # v0.0.3
ruff_text_size = { git = "https://github.com/astral-sh/RustPython-Parser.git", rev = "08ebbe40d7776cac6e3ba66277d435056f2b8dca" } ruff_text_size = { git = "https://github.com/astral-sh/RustPython-Parser.git", rev = "f60e204b73b95bdb6ce87ccd0de34081b4a17c11" }
# v0.0.3 # v0.0.3
rustpython-ast = { git = "https://github.com/astral-sh/RustPython-Parser.git", rev = "08ebbe40d7776cac6e3ba66277d435056f2b8dca" , default-features = false, features = ["all-nodes-with-ranges", "num-bigint"]} rustpython-ast = { git = "https://github.com/astral-sh/RustPython-Parser.git", rev = "f60e204b73b95bdb6ce87ccd0de34081b4a17c11" , default-features = false, features = ["all-nodes-with-ranges", "num-bigint"]}
# v0.0.3 # v0.0.3
rustpython-format = { git = "https://github.com/astral-sh/RustPython-Parser.git", rev = "08ebbe40d7776cac6e3ba66277d435056f2b8dca", default-features = false, features = ["num-bigint"] } rustpython-format = { git = "https://github.com/astral-sh/RustPython-Parser.git", rev = "f60e204b73b95bdb6ce87ccd0de34081b4a17c11", default-features = false, features = ["num-bigint"] }
# v0.0.3 # v0.0.3
rustpython-literal = { git = "https://github.com/astral-sh/RustPython-Parser.git", rev = "08ebbe40d7776cac6e3ba66277d435056f2b8dca", default-features = false } rustpython-literal = { git = "https://github.com/astral-sh/RustPython-Parser.git", rev = "f60e204b73b95bdb6ce87ccd0de34081b4a17c11", default-features = false }
# v0.0.3 # v0.0.3
rustpython-parser = { git = "https://github.com/astral-sh/RustPython-Parser.git", rev = "08ebbe40d7776cac6e3ba66277d435056f2b8dca" , default-features = false, features = ["full-lexer", "all-nodes-with-ranges", "num-bigint"] } rustpython-parser = { git = "https://github.com/astral-sh/RustPython-Parser.git", rev = "f60e204b73b95bdb6ce87ccd0de34081b4a17c11" , default-features = false, features = ["full-lexer", "all-nodes-with-ranges", "num-bigint"] }
[profile.release] [profile.release]
lto = "fat" lto = "fat"

View File

@ -0,0 +1,36 @@
class Test(
Aaaaaaaaaaaaaaaaa,
Bbbbbbbbbbbbbbbb,
DDDDDDDDDDDDDDDD,
EEEEEEEEEEEEEE,
metaclass=meta,
):
pass
class Test((Aaaaaaaaaaaaaaaaa), Bbbbbbbbbbbbbbbb, metaclass=meta):
pass
class Test( # trailing class comment
Aaaaaaaaaaaaaaaaa, # trailing comment
# in between comment
Bbbbbbbbbbbbbbbb,
# another leading comment
DDDDDDDDDDDDDDDD,
EEEEEEEEEEEEEE,
# meta comment
metaclass=meta, # trailing meta comment
):
pass
class Test((Aaaa)):
...
class Test(aaaaaaaaaaaaaaa + bbbbbbbbbbbbbbbbbbbbbb + cccccccccccccccccccccccc + dddddddddddddddddddddd + eeeeeeeee, ffffffffffffffffff, gggggggggggggggggg):
pass
class Test(Aaaa): # trailing comment
pass

View File

@ -582,6 +582,12 @@ fn handle_trailing_end_of_line_condition_comment<'a>(
.as_deref() .as_deref()
.map(AnyNodeRef::from) .map(AnyNodeRef::from)
.or_else(|| Some(AnyNodeRef::from(args.as_ref()))), .or_else(|| Some(AnyNodeRef::from(args.as_ref()))),
AnyNodeRef::StmtClassDef(StmtClassDef {
bases, keywords, ..
}) => keywords
.last()
.map(AnyNodeRef::from)
.or_else(|| bases.last().map(AnyNodeRef::from)),
_ => None, _ => None,
}; };
@ -622,8 +628,13 @@ fn handle_trailing_end_of_line_condition_comment<'a>(
TokenKind::RParen => { TokenKind::RParen => {
// Skip over any closing parentheses // Skip over any closing parentheses
} }
_ => { TokenKind::Comma => {
unreachable!("Only ')' or ':' should follow the condition") // Skip over any trailing comma
}
kind => {
unreachable!(
"Only ')' or ':' should follow the condition but encountered {kind:?}"
)
} }
} }
} }

View File

@ -26,6 +26,8 @@ pub(super) fn default_expression_needs_parentheses(
#[allow(clippy::if_same_then_else)] #[allow(clippy::if_same_then_else)]
if parenthesize.is_always() { if parenthesize.is_always() {
Parentheses::Always Parentheses::Always
} else if parenthesize.is_never() {
Parentheses::Never
} }
// `Optional` or `Preserve` and expression has parentheses in source code. // `Optional` or `Preserve` and expression has parentheses in source code.
else if !parenthesize.is_if_breaks() && is_expression_parenthesized(node, source) { else if !parenthesize.is_if_breaks() && is_expression_parenthesized(node, source) {
@ -58,7 +60,11 @@ pub enum Parenthesize {
/// Parenthesizes the expression only if it doesn't fit on a line. /// Parenthesizes the expression only if it doesn't fit on a line.
IfBreaks, IfBreaks,
/// Always adds parentheses
Always, Always,
/// Never adds parentheses. Parentheses are handled by the caller.
Never,
} }
impl Parenthesize { impl Parenthesize {
@ -66,6 +72,10 @@ impl Parenthesize {
matches!(self, Parenthesize::Always) matches!(self, Parenthesize::Always)
} }
pub(crate) const fn is_never(self) -> bool {
matches!(self, Parenthesize::Never)
}
pub(crate) const fn is_if_breaks(self) -> bool { pub(crate) const fn is_if_breaks(self) -> bool {
matches!(self, Parenthesize::IfBreaks) matches!(self, Parenthesize::IfBreaks)
} }

View File

@ -1,5 +1,6 @@
use crate::{not_yet_implemented, FormatNodeRule, PyFormatter}; use crate::prelude::*;
use ruff_formatter::{write, Buffer, FormatResult}; use crate::FormatNodeRule;
use ruff_formatter::write;
use rustpython_parser::ast::Keyword; use rustpython_parser::ast::Keyword;
#[derive(Default)] #[derive(Default)]
@ -7,6 +8,15 @@ pub struct FormatKeyword;
impl FormatNodeRule<Keyword> for FormatKeyword { impl FormatNodeRule<Keyword> for FormatKeyword {
fn fmt_fields(&self, item: &Keyword, f: &mut PyFormatter) -> FormatResult<()> { fn fmt_fields(&self, item: &Keyword, f: &mut PyFormatter) -> FormatResult<()> {
write!(f, [not_yet_implemented(item)]) let Keyword {
range: _,
arg,
value,
} = item;
if let Some(argument) = arg {
write!(f, [argument.format(), text("=")])?;
}
value.format().fmt(f)
} }
} }

View File

@ -1,135 +0,0 @@
---
source: crates/ruff_python_formatter/src/lib.rs
expression: snapshot
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/class_blank_parentheses.py
---
## Input
```py
class SimpleClassWithBlankParentheses():
pass
class ClassWithSpaceParentheses ( ):
first_test_data = 90
second_test_data = 100
def test_func(self):
return None
class ClassWithEmptyFunc(object):
def func_with_blank_parentheses():
return 5
def public_func_with_blank_parentheses():
return None
def class_under_the_func_with_blank_parentheses():
class InsideFunc():
pass
class NormalClass (
):
def func_for_testing(self, first, second):
sum = first + second
return sum
```
## Black Differences
```diff
--- Black
+++ Ruff
@@ -1,18 +1,10 @@
-class SimpleClassWithBlankParentheses:
- pass
+NOT_YET_IMPLEMENTED_StmtClassDef
-class ClassWithSpaceParentheses:
- first_test_data = 90
- second_test_data = 100
-
- def test_func(self):
- return None
+NOT_YET_IMPLEMENTED_StmtClassDef
-class ClassWithEmptyFunc(object):
- def func_with_blank_parentheses():
- return 5
+NOT_YET_IMPLEMENTED_StmtClassDef
def public_func_with_blank_parentheses():
@@ -20,11 +12,7 @@
def class_under_the_func_with_blank_parentheses():
- class InsideFunc:
- pass
+ NOT_YET_IMPLEMENTED_StmtClassDef
-class NormalClass:
- def func_for_testing(self, first, second):
- sum = first + second
- return sum
+NOT_YET_IMPLEMENTED_StmtClassDef
```
## Ruff Output
```py
NOT_YET_IMPLEMENTED_StmtClassDef
NOT_YET_IMPLEMENTED_StmtClassDef
NOT_YET_IMPLEMENTED_StmtClassDef
def public_func_with_blank_parentheses():
return None
def class_under_the_func_with_blank_parentheses():
NOT_YET_IMPLEMENTED_StmtClassDef
NOT_YET_IMPLEMENTED_StmtClassDef
```
## Black Output
```py
class SimpleClassWithBlankParentheses:
pass
class ClassWithSpaceParentheses:
first_test_data = 90
second_test_data = 100
def test_func(self):
return None
class ClassWithEmptyFunc(object):
def func_with_blank_parentheses():
return 5
def public_func_with_blank_parentheses():
return None
def class_under_the_func_with_blank_parentheses():
class InsideFunc:
pass
class NormalClass:
def func_for_testing(self, first, second):
sum = first + second
return sum
```

View File

@ -113,259 +113,257 @@ class ClassWithDecoInitAndVarsAndDocstringWithInner2:
```diff ```diff
--- Black --- Black
+++ Ruff +++ Ruff
@@ -1,165 +1,61 @@ @@ -7,7 +7,7 @@
-class ClassSimplest:
- pass
+NOT_YET_IMPLEMENTED_StmtClassDef
-class ClassWithSingleField: class ClassWithJustTheDocstring:
- a = 1
+NOT_YET_IMPLEMENTED_StmtClassDef
-class ClassWithJustTheDocstring:
- """Just a docstring.""" - """Just a docstring."""
+NOT_YET_IMPLEMENTED_StmtClassDef + "NOT_YET_IMPLEMENTED_STRING"
-class ClassWithInit: class ClassWithInit:
- def __init__(self): @@ -16,7 +16,7 @@
- pass
+NOT_YET_IMPLEMENTED_StmtClassDef
-class ClassWithTheDocstringAndInit: class ClassWithTheDocstringAndInit:
- """Just a docstring.""" - """Just a docstring."""
+NOT_YET_IMPLEMENTED_StmtClassDef + "NOT_YET_IMPLEMENTED_STRING"
- def __init__(self): def __init__(self):
- pass pass
@@ -30,8 +30,7 @@
+NOT_YET_IMPLEMENTED_StmtClassDef
-class ClassWithInitAndVars:
- cls_var = 100
- def __init__(self):
- pass
+NOT_YET_IMPLEMENTED_StmtClassDef
-class ClassWithInitAndVarsAndDocstring: class ClassWithInitAndVarsAndDocstring:
- """Test class""" - """Test class"""
+NOT_YET_IMPLEMENTED_StmtClassDef -
+ "NOT_YET_IMPLEMENTED_STRING"
cls_var = 100
- cls_var = 100 def __init__(self):
@@ -53,8 +52,7 @@
- def __init__(self):
- pass
+NOT_YET_IMPLEMENTED_StmtClassDef
-class ClassWithDecoInit: class ClassWithDecoInitAndVarsAndDocstring:
- @deco
- def __init__(self):
- pass
+NOT_YET_IMPLEMENTED_StmtClassDef
-class ClassWithDecoInitAndVars:
- cls_var = 100
+NOT_YET_IMPLEMENTED_StmtClassDef
- @deco
- def __init__(self):
- pass
+NOT_YET_IMPLEMENTED_StmtClassDef
-class ClassWithDecoInitAndVarsAndDocstring:
- """Test class""" - """Test class"""
-
+ "NOT_YET_IMPLEMENTED_STRING"
cls_var = 100
- cls_var = 100 @deco
+NOT_YET_IMPLEMENTED_StmtClassDef @@ -69,7 +67,7 @@
- @deco class ClassSimplestWithInnerWithDocstring:
- def __init__(self): class Inner:
- pass
+NOT_YET_IMPLEMENTED_StmtClassDef
-class ClassSimplestWithInner:
- class Inner:
- pass
+NOT_YET_IMPLEMENTED_StmtClassDef
-class ClassSimplestWithInnerWithDocstring:
- class Inner:
- """Just a docstring.""" - """Just a docstring."""
+ "NOT_YET_IMPLEMENTED_STRING"
- def __init__(self): def __init__(self):
- pass pass
+NOT_YET_IMPLEMENTED_StmtClassDef @@ -83,7 +81,7 @@
-class ClassWithSingleFieldWithInner: class ClassWithJustTheDocstringWithInner:
- a = 1
+NOT_YET_IMPLEMENTED_StmtClassDef
- class Inner:
- pass
+NOT_YET_IMPLEMENTED_StmtClassDef
-class ClassWithJustTheDocstringWithInner:
- """Just a docstring.""" - """Just a docstring."""
+ "NOT_YET_IMPLEMENTED_STRING"
- class Inner: class Inner:
- pass pass
+NOT_YET_IMPLEMENTED_StmtClassDef @@ -108,8 +106,7 @@
-class ClassWithInitWithInner: class ClassWithInitAndVarsAndDocstringWithInner:
- class Inner:
- pass
-
- def __init__(self):
- pass
-
-
-class ClassWithInitAndVarsWithInner:
- cls_var = 100
-
- class Inner:
- pass
-
- def __init__(self):
- pass
-
-
-class ClassWithInitAndVarsAndDocstringWithInner:
- """Test class""" - """Test class"""
- -
- cls_var = 100 + "NOT_YET_IMPLEMENTED_STRING"
- cls_var = 100
- class Inner:
- pass class Inner:
- @@ -140,8 +137,7 @@
- def __init__(self):
- pass
-
-
-class ClassWithDecoInitWithInner:
- class Inner:
- pass
-
- @deco
- def __init__(self):
- pass
+NOT_YET_IMPLEMENTED_StmtClassDef
-class ClassWithDecoInitAndVarsWithInner: class ClassWithDecoInitAndVarsAndDocstringWithInner:
- cls_var = 100
-
- class Inner:
- pass
-
- @deco
- def __init__(self):
- pass
-
-
-class ClassWithDecoInitAndVarsAndDocstringWithInner:
- """Test class""" - """Test class"""
- -
- cls_var = 100 + "NOT_YET_IMPLEMENTED_STRING"
- cls_var = 100
- class Inner:
- pass class Inner:
- @@ -153,7 +149,7 @@
- @deco
- def __init__(self):
- pass class ClassWithDecoInitAndVarsAndDocstringWithInner2:
-
-
-class ClassWithDecoInitAndVarsAndDocstringWithInner2:
- """Test class""" - """Test class"""
- + "NOT_YET_IMPLEMENTED_STRING"
- class Inner:
- pass class Inner:
- pass
- cls_var = 100
-
- @deco
- def __init__(self):
- pass
+NOT_YET_IMPLEMENTED_StmtClassDef
``` ```
## Ruff Output ## Ruff Output
```py ```py
NOT_YET_IMPLEMENTED_StmtClassDef class ClassSimplest:
pass
NOT_YET_IMPLEMENTED_StmtClassDef class ClassWithSingleField:
a = 1
NOT_YET_IMPLEMENTED_StmtClassDef class ClassWithJustTheDocstring:
"NOT_YET_IMPLEMENTED_STRING"
NOT_YET_IMPLEMENTED_StmtClassDef class ClassWithInit:
def __init__(self):
pass
NOT_YET_IMPLEMENTED_StmtClassDef class ClassWithTheDocstringAndInit:
"NOT_YET_IMPLEMENTED_STRING"
def __init__(self):
pass
NOT_YET_IMPLEMENTED_StmtClassDef class ClassWithInitAndVars:
cls_var = 100
def __init__(self):
pass
NOT_YET_IMPLEMENTED_StmtClassDef class ClassWithInitAndVarsAndDocstring:
"NOT_YET_IMPLEMENTED_STRING"
cls_var = 100
def __init__(self):
pass
NOT_YET_IMPLEMENTED_StmtClassDef class ClassWithDecoInit:
@deco
def __init__(self):
pass
NOT_YET_IMPLEMENTED_StmtClassDef class ClassWithDecoInitAndVars:
cls_var = 100
@deco
def __init__(self):
pass
NOT_YET_IMPLEMENTED_StmtClassDef class ClassWithDecoInitAndVarsAndDocstring:
"NOT_YET_IMPLEMENTED_STRING"
cls_var = 100
@deco
def __init__(self):
pass
NOT_YET_IMPLEMENTED_StmtClassDef class ClassSimplestWithInner:
class Inner:
pass
NOT_YET_IMPLEMENTED_StmtClassDef class ClassSimplestWithInnerWithDocstring:
class Inner:
"NOT_YET_IMPLEMENTED_STRING"
def __init__(self):
pass
NOT_YET_IMPLEMENTED_StmtClassDef class ClassWithSingleFieldWithInner:
a = 1
class Inner:
pass
NOT_YET_IMPLEMENTED_StmtClassDef class ClassWithJustTheDocstringWithInner:
"NOT_YET_IMPLEMENTED_STRING"
class Inner:
pass
NOT_YET_IMPLEMENTED_StmtClassDef class ClassWithInitWithInner:
class Inner:
pass
def __init__(self):
pass
NOT_YET_IMPLEMENTED_StmtClassDef class ClassWithInitAndVarsWithInner:
cls_var = 100
class Inner:
pass
def __init__(self):
pass
NOT_YET_IMPLEMENTED_StmtClassDef class ClassWithInitAndVarsAndDocstringWithInner:
"NOT_YET_IMPLEMENTED_STRING"
cls_var = 100
class Inner:
pass
def __init__(self):
pass
NOT_YET_IMPLEMENTED_StmtClassDef class ClassWithDecoInitWithInner:
class Inner:
pass
@deco
def __init__(self):
pass
NOT_YET_IMPLEMENTED_StmtClassDef class ClassWithDecoInitAndVarsWithInner:
cls_var = 100
class Inner:
pass
@deco
def __init__(self):
pass
NOT_YET_IMPLEMENTED_StmtClassDef class ClassWithDecoInitAndVarsAndDocstringWithInner:
"NOT_YET_IMPLEMENTED_STRING"
cls_var = 100
class Inner:
pass
@deco
def __init__(self):
pass
NOT_YET_IMPLEMENTED_StmtClassDef class ClassWithDecoInitAndVarsAndDocstringWithInner2:
"NOT_YET_IMPLEMENTED_STRING"
class Inner:
pass
cls_var = 100
@deco
def __init__(self):
pass
``` ```
## Black Output ## Black Output

View File

@ -349,7 +349,7 @@ instruction()#comment with bad spacing
while True: while True:
if False: if False:
continue continue
@@ -141,25 +111,13 @@ @@ -141,24 +111,18 @@
# and round and round we go # and round and round we go
# let's return # let's return
@ -370,15 +370,17 @@ instruction()#comment with bad spacing
+CONFIG_FILES = [CONFIG_FILE] + SHARED_CONFIG_FILES + USER_CONFIG_FILES # type: Final +CONFIG_FILES = [CONFIG_FILE] + SHARED_CONFIG_FILES + USER_CONFIG_FILES # type: Final
-class Test: class Test:
- def _init_host(self, parsed) -> None: def _init_host(self, parsed) -> None:
- if parsed.hostname is None or not parsed.hostname.strip(): # type: ignore - if parsed.hostname is None or not parsed.hostname.strip(): # type: ignore
- pass + if (
+NOT_YET_IMPLEMENTED_StmtClassDef + NOT_IMPLEMENTED_left < NOT_IMPLEMENTED_right # type: ignore
+ or not NOT_IMPLEMENTED_call()
+ ):
pass
####################### @@ -167,7 +131,7 @@
@@ -167,7 +125,7 @@
####################### #######################
@ -511,7 +513,13 @@ def inline_comments_in_brackets_ruin_everything():
CONFIG_FILES = [CONFIG_FILE] + SHARED_CONFIG_FILES + USER_CONFIG_FILES # type: Final CONFIG_FILES = [CONFIG_FILE] + SHARED_CONFIG_FILES + USER_CONFIG_FILES # type: Final
NOT_YET_IMPLEMENTED_StmtClassDef class Test:
def _init_host(self, parsed) -> None:
if (
NOT_IMPLEMENTED_left < NOT_IMPLEMENTED_right # type: ignore
or not NOT_IMPLEMENTED_call()
):
pass
####################### #######################

View File

@ -107,7 +107,7 @@ def foo3(list_a, list_b):
```diff ```diff
--- Black --- Black
+++ Ruff +++ Ruff
@@ -1,94 +1,22 @@ @@ -1,94 +1,28 @@
-from com.my_lovely_company.my_lovely_team.my_lovely_project.my_lovely_component import ( -from com.my_lovely_company.my_lovely_team.my_lovely_project.my_lovely_component import (
- MyLovelyCompanyTeamProjectComponent, # NOT DRY - MyLovelyCompanyTeamProjectComponent, # NOT DRY
-) -)
@ -118,7 +118,7 @@ def foo3(list_a, list_b):
+NOT_YET_IMPLEMENTED_StmtImportFrom +NOT_YET_IMPLEMENTED_StmtImportFrom
-class C: class C:
- @pytest.mark.parametrize( - @pytest.mark.parametrize(
- ("post_data", "message"), - ("post_data", "message"),
- [ - [
@ -161,12 +161,14 @@ def foo3(list_a, list_b):
- ), - ),
- ], - ],
- ) - )
- def test_fails_invalid_post_data( + @NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg)
- self, pyramid_config, db_request, post_data, message def test_fails_invalid_post_data(
- ): self, pyramid_config, db_request, post_data, message
):
- pyramid_config.testing_securitypolicy(userid=1) - pyramid_config.testing_securitypolicy(userid=1)
- db_request.POST = MultiDict(post_data) - db_request.POST = MultiDict(post_data)
+NOT_YET_IMPLEMENTED_StmtClassDef + NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg)
+ db_request.POST = NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg)
def foo(list_a, list_b): def foo(list_a, list_b):
@ -217,7 +219,13 @@ NOT_YET_IMPLEMENTED_StmtImportFrom
NOT_YET_IMPLEMENTED_StmtImportFrom NOT_YET_IMPLEMENTED_StmtImportFrom
NOT_YET_IMPLEMENTED_StmtClassDef class C:
@NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg)
def test_fails_invalid_post_data(
self, pyramid_config, db_request, post_data, message
):
NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg)
db_request.POST = NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg)
def foo(list_a, list_b): def foo(list_a, list_b):

View File

@ -152,38 +152,16 @@ def bar():
```diff ```diff
--- Black --- Black
+++ Ruff +++ Ruff
@@ -30,8 +30,7 @@ @@ -44,7 +44,7 @@
# This comment should be split from the statement above by two lines. class ClassWithDocstring:
-class MyClass:
- pass
+NOT_YET_IMPLEMENTED_StmtClassDef
some = statement
@@ -39,17 +38,14 @@
# This should be split from the above by two lines
-class MyClassWithComplexLeadingComments:
- pass
+NOT_YET_IMPLEMENTED_StmtClassDef
-class ClassWithDocstring:
- """A docstring.""" - """A docstring."""
+NOT_YET_IMPLEMENTED_StmtClassDef + "NOT_YET_IMPLEMENTED_STRING"
# Leading comment after a class with just a docstring # Leading comment after a class with just a docstring
-class MyClassAfterAnotherClassWithDocstring: @@ -59,7 +59,7 @@
- pass
+NOT_YET_IMPLEMENTED_StmtClassDef
some = statement
@@ -59,7 +55,7 @@
@deco1 @deco1
# leading 2 # leading 2
# leading 2 extra # leading 2 extra
@ -192,7 +170,7 @@ def bar():
# leading 3 # leading 3
@deco3 @deco3
# leading 4 # leading 4
@@ -73,7 +69,7 @@ @@ -73,7 +73,7 @@
# leading 1 # leading 1
@deco1 @deco1
# leading 2 # leading 2
@ -201,7 +179,7 @@ def bar():
# leading 3 that already has an empty line # leading 3 that already has an empty line
@deco3 @deco3
@@ -88,7 +84,7 @@ @@ -88,7 +88,7 @@
# leading 1 # leading 1
@deco1 @deco1
# leading 2 # leading 2
@ -210,7 +188,7 @@ def bar():
# leading 3 # leading 3
@deco3 @deco3
@@ -106,7 +102,6 @@ @@ -106,7 +106,6 @@
# Another leading comment # Another leading comment
def another_inline(): def another_inline():
pass pass
@ -218,7 +196,7 @@ def bar():
else: else:
# More leading comments # More leading comments
def inline_after_else(): def inline_after_else():
@@ -121,18 +116,13 @@ @@ -121,7 +120,6 @@
# Another leading comment # Another leading comment
def another_top_level_quote_inline_inline(): def another_top_level_quote_inline_inline():
pass pass
@ -226,18 +204,6 @@ def bar():
else: else:
# More leading comments # More leading comments
def top_level_quote_inline_after_else(): def top_level_quote_inline_after_else():
pass
-class MyClass:
- # First method has no empty lines between bare class def.
- # More comments.
- def first_method(self):
- pass
+NOT_YET_IMPLEMENTED_StmtClassDef
# Regression test for https://github.com/psf/black/issues/3454.
``` ```
## Ruff Output ## Ruff Output
@ -275,7 +241,8 @@ some = statement
# This comment should be split from the statement above by two lines. # This comment should be split from the statement above by two lines.
NOT_YET_IMPLEMENTED_StmtClassDef class MyClass:
pass
some = statement some = statement
@ -283,14 +250,17 @@ some = statement
# This should be split from the above by two lines # This should be split from the above by two lines
NOT_YET_IMPLEMENTED_StmtClassDef class MyClassWithComplexLeadingComments:
pass
NOT_YET_IMPLEMENTED_StmtClassDef class ClassWithDocstring:
"NOT_YET_IMPLEMENTED_STRING"
# Leading comment after a class with just a docstring # Leading comment after a class with just a docstring
NOT_YET_IMPLEMENTED_StmtClassDef class MyClassAfterAnotherClassWithDocstring:
pass
some = statement some = statement
@ -367,7 +337,11 @@ else:
pass pass
NOT_YET_IMPLEMENTED_StmtClassDef class MyClass:
# First method has no empty lines between bare class def.
# More comments.
def first_method(self):
pass
# Regression test for https://github.com/psf/black/issues/3454. # Regression test for https://github.com/psf/black/issues/3454.

View File

@ -114,16 +114,16 @@ async def wat():
# Has many lines. Many, many lines. # Has many lines. Many, many lines.
# Many, many, many lines. # Many, many, many lines.
-"""Module docstring. -"""Module docstring.
- +"NOT_YET_IMPLEMENTED_STRING"
-Possibly also many, many lines. -Possibly also many, many lines.
-""" -"""
+"NOT_YET_IMPLEMENTED_STRING" +NOT_YET_IMPLEMENTED_StmtImport
+NOT_YET_IMPLEMENTED_StmtImport
-import os.path -import os.path
-import sys -import sys
+NOT_YET_IMPLEMENTED_StmtImport -
+NOT_YET_IMPLEMENTED_StmtImport
-import a -import a
-from b.c import X # some noqa comment -from b.c import X # some noqa comment
+NOT_YET_IMPLEMENTED_StmtImport +NOT_YET_IMPLEMENTED_StmtImport
@ -137,7 +137,7 @@ async def wat():
# Some comment before a function. # Some comment before a function.
@@ -30,67 +24,50 @@ @@ -30,25 +24,26 @@
def function(default=None): def function(default=None):
@ -173,28 +173,29 @@ async def wat():
# Another comment! # Another comment!
# This time two lines. @@ -56,7 +51,7 @@
-class Foo: class Foo:
- """Docstring for class Foo. Example from Sphinx docs.""" - """Docstring for class Foo. Example from Sphinx docs."""
- + "NOT_YET_IMPLEMENTED_STRING"
- #: Doc comment for class attribute Foo.bar.
- #: It can have multiple lines. #: Doc comment for class attribute Foo.bar.
- bar = 1 #: It can have multiple lines.
- @@ -65,32 +60,31 @@
- flox = 1.5 #: Doc comment for Foo.flox. One line only. flox = 1.5 #: Doc comment for Foo.flox. One line only.
-
- baz = 2 baz = 2
- """Docstring for class attribute Foo.baz.""" - """Docstring for class attribute Foo.baz."""
- + "NOT_YET_IMPLEMENTED_STRING"
- def __init__(self):
- #: Doc comment for instance attribute qux. def __init__(self):
- self.qux = 3 #: Doc comment for instance attribute qux.
- self.qux = 3
- self.spam = 4
self.spam = 4
- """Docstring for instance attribute spam.""" - """Docstring for instance attribute spam."""
+NOT_YET_IMPLEMENTED_StmtClassDef + "NOT_YET_IMPLEMENTED_STRING"
#' <h1>This is pweave!</h1> #' <h1>This is pweave!</h1>
@ -279,7 +280,24 @@ GLOBAL_STATE = {
# This time two lines. # This time two lines.
NOT_YET_IMPLEMENTED_StmtClassDef class Foo:
"NOT_YET_IMPLEMENTED_STRING"
#: 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
"NOT_YET_IMPLEMENTED_STRING"
def __init__(self):
#: Doc comment for instance attribute qux.
self.qux = 3
self.spam = 4
"NOT_YET_IMPLEMENTED_STRING"
#' <h1>This is pweave!</h1> #' <h1>This is pweave!</h1>

View File

@ -194,9 +194,9 @@ class C:
```diff ```diff
--- Black --- Black
+++ Ruff +++ Ruff
@@ -1,181 +1 @@ @@ -1,181 +1,46 @@
-class C: class C:
- def test(self) -> None: def test(self) -> None:
- with patch("black.out", print): - with patch("black.out", print):
- self.assertEqual( - self.assertEqual(
- unstyle(str(report)), "1 file reformatted, 1 file failed to reformat." - unstyle(str(report)), "1 file reformatted, 1 file failed to reformat."
@ -239,23 +239,38 @@ class C:
- return ( - return (
- 'Utterly failed doctest test for %s\n File "%s", line %s, in %s\n\n%s' - 'Utterly failed doctest test for %s\n File "%s", line %s, in %s\n\n%s'
- % (test.name, test.filename, lineno, lname, err) - % (test.name, test.filename, lineno, lname, err)
- ) + NOT_YET_IMPLEMENTED_StmtWith
- + xxxxxxxxxxxxxxxx = NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg)
- def omitting_trailers(self) -> None: + return "NOT_YET_IMPLEMENTED_STRING" % (
+ test.name,
+ test.filename,
+ lineno,
+ lname,
+ err,
)
def omitting_trailers(self) -> None:
- get_collection( - get_collection(
- hey_this_is_a_very_long_call, it_has_funny_attributes, really=True - hey_this_is_a_very_long_call, it_has_funny_attributes, really=True
- )[OneLevelIndex] - )[OneLevelIndex]
- get_collection( - get_collection(
- hey_this_is_a_very_long_call, it_has_funny_attributes, really=True - hey_this_is_a_very_long_call, it_has_funny_attributes, really=True
- )[OneLevelIndex][TwoLevelIndex][ThreeLevelIndex][FourLevelIndex] - )[OneLevelIndex][TwoLevelIndex][ThreeLevelIndex][FourLevelIndex]
- d[0][1][2][3][4][5][6][7][8][9][10][11][12][13][14][15][16][17][18][19][20][21][ + NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg)[OneLevelIndex]
- 22 + NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg)[OneLevelIndex][TwoLevelIndex][
- ] + ThreeLevelIndex
+ ][
+ FourLevelIndex
+ ]
d[0][1][2][3][4][5][6][7][8][9][10][11][12][13][14][15][16][17][18][19][20][21][
22
]
- assignment = ( - assignment = (
- some.rather.elaborate.rule() and another.rule.ending_with.index[123] - some.rather.elaborate.rule() and another.rule.ending_with.index[123]
- ) - )
- + assignment = NOT_IMPLEMENTED_call() and another.rule.ending_with.index[123]
- def easy_asserts(self) -> None:
def easy_asserts(self) -> None:
- assert { - assert {
- key1: value1, - key1: value1,
- key2: value2, - key2: value2,
@ -267,7 +282,8 @@ class C:
- key8: value8, - key8: value8,
- key9: value9, - key9: value9,
- } == expected, "Not what we expected" - } == expected, "Not what we expected"
- + NOT_YET_IMPLEMENTED_StmtAssert
- assert expected == { - assert expected == {
- key1: value1, - key1: value1,
- key2: value2, - key2: value2,
@ -279,7 +295,8 @@ class C:
- key8: value8, - key8: value8,
- key9: value9, - key9: value9,
- }, "Not what we expected" - }, "Not what we expected"
- + NOT_YET_IMPLEMENTED_StmtAssert
- assert expected == { - assert expected == {
- key1: value1, - key1: value1,
- key2: value2, - key2: value2,
@ -291,8 +308,9 @@ class C:
- key8: value8, - key8: value8,
- key9: value9, - key9: value9,
- } - }
- + NOT_YET_IMPLEMENTED_StmtAssert
- def tricky_asserts(self) -> None:
def tricky_asserts(self) -> None:
- assert { - assert {
- key1: value1, - key1: value1,
- key2: value2, - key2: value2,
@ -306,7 +324,8 @@ class C:
- } == expected( - } == expected(
- value, is_going_to_be="too long to fit in a single line", srsly=True - value, is_going_to_be="too long to fit in a single line", srsly=True
- ), "Not what we expected" - ), "Not what we expected"
- + NOT_YET_IMPLEMENTED_StmtAssert
- assert { - assert {
- key1: value1, - key1: value1,
- key2: value2, - key2: value2,
@ -320,7 +339,8 @@ class C:
- } == expected, ( - } == expected, (
- "Not what we expected and the message is too long to fit in one line" - "Not what we expected and the message is too long to fit in one line"
- ) - )
- + NOT_YET_IMPLEMENTED_StmtAssert
- assert expected( - assert expected(
- value, is_going_to_be="too long to fit in a single line", srsly=True - value, is_going_to_be="too long to fit in a single line", srsly=True
- ) == { - ) == {
@ -334,7 +354,8 @@ class C:
- key8: value8, - key8: value8,
- key9: value9, - key9: value9,
- }, "Not what we expected" - }, "Not what we expected"
- + NOT_YET_IMPLEMENTED_StmtAssert
- assert expected == { - assert expected == {
- key1: value1, - key1: value1,
- key2: value2, - key2: value2,
@ -349,7 +370,8 @@ class C:
- "Not what we expected and the message is too long to fit in one line" - "Not what we expected and the message is too long to fit in one line"
- " because it's too long" - " because it's too long"
- ) - )
- + NOT_YET_IMPLEMENTED_StmtAssert
- dis_c_instance_method = """\ - dis_c_instance_method = """\
- %3d 0 LOAD_FAST 1 (x) - %3d 0 LOAD_FAST 1 (x)
- 2 LOAD_CONST 1 (1) - 2 LOAD_CONST 1 (1)
@ -360,8 +382,11 @@ class C:
- 12 RETURN_VALUE - 12 RETURN_VALUE
- """ % ( - """ % (
- _C.__init__.__code__.co_firstlineno + 1, - _C.__init__.__code__.co_firstlineno + 1,
- ) + dis_c_instance_method = "NOT_YET_IMPLEMENTED_STRING" % (
- + _C.__init__.__code__.co_firstlineno
+ + 1,
)
- assert ( - assert (
- expectedexpectedexpectedexpectedexpectedexpectedexpectedexpectedexpect - expectedexpectedexpectedexpectedexpectedexpectedexpectedexpectedexpect
- == { - == {
@ -376,13 +401,58 @@ class C:
- key9: value9, - key9: value9,
- } - }
- ) - )
+NOT_YET_IMPLEMENTED_StmtClassDef + NOT_YET_IMPLEMENTED_StmtAssert
``` ```
## Ruff Output ## Ruff Output
```py ```py
NOT_YET_IMPLEMENTED_StmtClassDef class C:
def test(self) -> None:
NOT_YET_IMPLEMENTED_StmtWith
xxxxxxxxxxxxxxxx = NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg)
return "NOT_YET_IMPLEMENTED_STRING" % (
test.name,
test.filename,
lineno,
lname,
err,
)
def omitting_trailers(self) -> None:
NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg)[OneLevelIndex]
NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg)[OneLevelIndex][TwoLevelIndex][
ThreeLevelIndex
][
FourLevelIndex
]
d[0][1][2][3][4][5][6][7][8][9][10][11][12][13][14][15][16][17][18][19][20][21][
22
]
assignment = NOT_IMPLEMENTED_call() and another.rule.ending_with.index[123]
def easy_asserts(self) -> None:
NOT_YET_IMPLEMENTED_StmtAssert
NOT_YET_IMPLEMENTED_StmtAssert
NOT_YET_IMPLEMENTED_StmtAssert
def tricky_asserts(self) -> None:
NOT_YET_IMPLEMENTED_StmtAssert
NOT_YET_IMPLEMENTED_StmtAssert
NOT_YET_IMPLEMENTED_StmtAssert
NOT_YET_IMPLEMENTED_StmtAssert
dis_c_instance_method = "NOT_YET_IMPLEMENTED_STRING" % (
_C.__init__.__code__.co_firstlineno
+ 1,
)
NOT_YET_IMPLEMENTED_StmtAssert
``` ```
## Black Output ## Black Output

View File

@ -194,9 +194,9 @@ class C:
```diff ```diff
--- Black --- Black
+++ Ruff +++ Ruff
@@ -1,181 +1 @@ @@ -1,181 +1,46 @@
-class C: class C:
- def test(self) -> None: def test(self) -> None:
- with patch("black.out", print): - with patch("black.out", print):
- self.assertEqual( - self.assertEqual(
- unstyle(str(report)), "1 file reformatted, 1 file failed to reformat." - unstyle(str(report)), "1 file reformatted, 1 file failed to reformat."
@ -239,23 +239,38 @@ class C:
- return ( - return (
- 'Utterly failed doctest test for %s\n File "%s", line %s, in %s\n\n%s' - 'Utterly failed doctest test for %s\n File "%s", line %s, in %s\n\n%s'
- % (test.name, test.filename, lineno, lname, err) - % (test.name, test.filename, lineno, lname, err)
- ) + NOT_YET_IMPLEMENTED_StmtWith
- + xxxxxxxxxxxxxxxx = NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg)
- def omitting_trailers(self) -> None: + return "NOT_YET_IMPLEMENTED_STRING" % (
+ test.name,
+ test.filename,
+ lineno,
+ lname,
+ err,
)
def omitting_trailers(self) -> None:
- get_collection( - get_collection(
- hey_this_is_a_very_long_call, it_has_funny_attributes, really=True - hey_this_is_a_very_long_call, it_has_funny_attributes, really=True
- )[OneLevelIndex] - )[OneLevelIndex]
- get_collection( - get_collection(
- hey_this_is_a_very_long_call, it_has_funny_attributes, really=True - hey_this_is_a_very_long_call, it_has_funny_attributes, really=True
- )[OneLevelIndex][TwoLevelIndex][ThreeLevelIndex][FourLevelIndex] - )[OneLevelIndex][TwoLevelIndex][ThreeLevelIndex][FourLevelIndex]
- d[0][1][2][3][4][5][6][7][8][9][10][11][12][13][14][15][16][17][18][19][20][21][ + NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg)[OneLevelIndex]
- 22 + NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg)[OneLevelIndex][TwoLevelIndex][
- ] + ThreeLevelIndex
+ ][
+ FourLevelIndex
+ ]
d[0][1][2][3][4][5][6][7][8][9][10][11][12][13][14][15][16][17][18][19][20][21][
22
]
- assignment = ( - assignment = (
- some.rather.elaborate.rule() and another.rule.ending_with.index[123] - some.rather.elaborate.rule() and another.rule.ending_with.index[123]
- ) - )
- + assignment = NOT_IMPLEMENTED_call() and another.rule.ending_with.index[123]
- def easy_asserts(self) -> None:
def easy_asserts(self) -> None:
- assert { - assert {
- key1: value1, - key1: value1,
- key2: value2, - key2: value2,
@ -267,7 +282,8 @@ class C:
- key8: value8, - key8: value8,
- key9: value9, - key9: value9,
- } == expected, "Not what we expected" - } == expected, "Not what we expected"
- + NOT_YET_IMPLEMENTED_StmtAssert
- assert expected == { - assert expected == {
- key1: value1, - key1: value1,
- key2: value2, - key2: value2,
@ -279,7 +295,8 @@ class C:
- key8: value8, - key8: value8,
- key9: value9, - key9: value9,
- }, "Not what we expected" - }, "Not what we expected"
- + NOT_YET_IMPLEMENTED_StmtAssert
- assert expected == { - assert expected == {
- key1: value1, - key1: value1,
- key2: value2, - key2: value2,
@ -291,8 +308,9 @@ class C:
- key8: value8, - key8: value8,
- key9: value9, - key9: value9,
- } - }
- + NOT_YET_IMPLEMENTED_StmtAssert
- def tricky_asserts(self) -> None:
def tricky_asserts(self) -> None:
- assert { - assert {
- key1: value1, - key1: value1,
- key2: value2, - key2: value2,
@ -306,7 +324,8 @@ class C:
- } == expected( - } == expected(
- value, is_going_to_be="too long to fit in a single line", srsly=True - value, is_going_to_be="too long to fit in a single line", srsly=True
- ), "Not what we expected" - ), "Not what we expected"
- + NOT_YET_IMPLEMENTED_StmtAssert
- assert { - assert {
- key1: value1, - key1: value1,
- key2: value2, - key2: value2,
@ -320,7 +339,8 @@ class C:
- } == expected, ( - } == expected, (
- "Not what we expected and the message is too long to fit in one line" - "Not what we expected and the message is too long to fit in one line"
- ) - )
- + NOT_YET_IMPLEMENTED_StmtAssert
- assert expected( - assert expected(
- value, is_going_to_be="too long to fit in a single line", srsly=True - value, is_going_to_be="too long to fit in a single line", srsly=True
- ) == { - ) == {
@ -334,7 +354,8 @@ class C:
- key8: value8, - key8: value8,
- key9: value9, - key9: value9,
- }, "Not what we expected" - }, "Not what we expected"
- + NOT_YET_IMPLEMENTED_StmtAssert
- assert expected == { - assert expected == {
- key1: value1, - key1: value1,
- key2: value2, - key2: value2,
@ -349,7 +370,8 @@ class C:
- "Not what we expected and the message is too long to fit in one line" - "Not what we expected and the message is too long to fit in one line"
- " because it's too long" - " because it's too long"
- ) - )
- + NOT_YET_IMPLEMENTED_StmtAssert
- dis_c_instance_method = """\ - dis_c_instance_method = """\
- %3d 0 LOAD_FAST 1 (x) - %3d 0 LOAD_FAST 1 (x)
- 2 LOAD_CONST 1 (1) - 2 LOAD_CONST 1 (1)
@ -360,8 +382,11 @@ class C:
- 12 RETURN_VALUE - 12 RETURN_VALUE
- """ % ( - """ % (
- _C.__init__.__code__.co_firstlineno + 1, - _C.__init__.__code__.co_firstlineno + 1,
- ) + dis_c_instance_method = "NOT_YET_IMPLEMENTED_STRING" % (
- + _C.__init__.__code__.co_firstlineno
+ + 1,
)
- assert ( - assert (
- expectedexpectedexpectedexpectedexpectedexpectedexpectedexpectedexpect - expectedexpectedexpectedexpectedexpectedexpectedexpectedexpectedexpect
- == { - == {
@ -376,13 +401,58 @@ class C:
- key9: value9, - key9: value9,
- } - }
- ) - )
+NOT_YET_IMPLEMENTED_StmtClassDef + NOT_YET_IMPLEMENTED_StmtAssert
``` ```
## Ruff Output ## Ruff Output
```py ```py
NOT_YET_IMPLEMENTED_StmtClassDef class C:
def test(self) -> None:
NOT_YET_IMPLEMENTED_StmtWith
xxxxxxxxxxxxxxxx = NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg)
return "NOT_YET_IMPLEMENTED_STRING" % (
test.name,
test.filename,
lineno,
lname,
err,
)
def omitting_trailers(self) -> None:
NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg)[OneLevelIndex]
NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg)[OneLevelIndex][TwoLevelIndex][
ThreeLevelIndex
][
FourLevelIndex
]
d[0][1][2][3][4][5][6][7][8][9][10][11][12][13][14][15][16][17][18][19][20][21][
22
]
assignment = NOT_IMPLEMENTED_call() and another.rule.ending_with.index[123]
def easy_asserts(self) -> None:
NOT_YET_IMPLEMENTED_StmtAssert
NOT_YET_IMPLEMENTED_StmtAssert
NOT_YET_IMPLEMENTED_StmtAssert
def tricky_asserts(self) -> None:
NOT_YET_IMPLEMENTED_StmtAssert
NOT_YET_IMPLEMENTED_StmtAssert
NOT_YET_IMPLEMENTED_StmtAssert
NOT_YET_IMPLEMENTED_StmtAssert
dis_c_instance_method = "NOT_YET_IMPLEMENTED_STRING" % (
_C.__init__.__code__.co_firstlineno
+ 1,
)
NOT_YET_IMPLEMENTED_StmtAssert
``` ```
## Black Output ## Black Output

View File

@ -17,12 +17,12 @@ class ClassWithDocstring:
```diff ```diff
--- Black --- Black
+++ Ruff +++ Ruff
@@ -1,4 +1,3 @@ @@ -1,4 +1,4 @@
# Make sure when the file ends with class's docstring, # Make sure when the file ends with class's docstring,
# It doesn't add extra blank lines. # It doesn't add extra blank lines.
-class ClassWithDocstring: class ClassWithDocstring:
- """A docstring.""" - """A docstring."""
+NOT_YET_IMPLEMENTED_StmtClassDef + "NOT_YET_IMPLEMENTED_STRING"
``` ```
## Ruff Output ## Ruff Output
@ -30,7 +30,8 @@ class ClassWithDocstring:
```py ```py
# Make sure when the file ends with class's docstring, # Make sure when the file ends with class's docstring,
# It doesn't add extra blank lines. # It doesn't add extra blank lines.
NOT_YET_IMPLEMENTED_StmtClassDef class ClassWithDocstring:
"NOT_YET_IMPLEMENTED_STRING"
``` ```
## Black Output ## Black Output

View File

@ -234,18 +234,19 @@ def stable_quote_normalization_with_immediate_inner_single_quote(self):
```diff ```diff
--- Black --- Black
+++ Ruff +++ Ruff
@@ -1,219 +1,149 @@ @@ -1,219 +1,154 @@
-class MyClass: class MyClass:
- """Multiline - """Multiline
- class docstring - class docstring
- """ - """
- + "NOT_YET_IMPLEMENTED_STRING"
- def method(self):
def method(self):
- """Multiline - """Multiline
- method docstring - method docstring
- """ - """
- pass + "NOT_YET_IMPLEMENTED_STRING"
+NOT_YET_IMPLEMENTED_StmtClassDef pass
def foo(): def foo():
@ -396,12 +397,12 @@ def stable_quote_normalization_with_immediate_inner_single_quote(self):
- tab at start of line and then a tab separated value - tab at start of line and then a tab separated value
- multiple tabs at the beginning and inline - multiple tabs at the beginning and inline
- mixed tabs and spaces at beginning. next line has mixed tabs and spaces only. - mixed tabs and spaces at beginning. next line has mixed tabs and spaces only.
-
- line ends with some tabs
- """
+ "NOT_YET_IMPLEMENTED_STRING" + "NOT_YET_IMPLEMENTED_STRING"
- line ends with some tabs
- """
-
def docstring_with_inline_tabs_and_tab_indentation(): def docstring_with_inline_tabs_and_tab_indentation():
- """hey - """hey
- -
@ -494,7 +495,12 @@ def stable_quote_normalization_with_immediate_inner_single_quote(self):
## Ruff Output ## Ruff Output
```py ```py
NOT_YET_IMPLEMENTED_StmtClassDef class MyClass:
"NOT_YET_IMPLEMENTED_STRING"
def method(self):
"NOT_YET_IMPLEMENTED_STRING"
pass
def foo(): def foo():

View File

@ -134,7 +134,7 @@ elif unformatted:
return True return True
# yapf: enable # yapf: enable
elif b: elif b:
@@ -39,49 +21,29 @@ @@ -39,12 +21,12 @@
# Regression test for https://github.com/psf/black/issues/2567. # Regression test for https://github.com/psf/black/issues/2567.
if True: if True:
# fmt: off # fmt: off
@ -152,40 +152,44 @@ elif unformatted:
# Regression test for https://github.com/psf/black/issues/3184. # Regression test for https://github.com/psf/black/issues/3184.
-class A: @@ -52,29 +34,27 @@
- async def call(param): async def call(param):
- if param: if param:
- # fmt: off # fmt: off
- if param[0:4] in ( - if param[0:4] in (
- "ABCD", "EFGH" - "ABCD", "EFGH"
- ) : - ) :
- # fmt: on + if NOT_IMPLEMENTED_left < NOT_IMPLEMENTED_right:
# fmt: on
- print ( "This won't be formatted" ) - print ( "This won't be formatted" )
- + NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg)
- elif param[0:4] in ("ZZZZ",): - elif param[0:4] in ("ZZZZ",):
- print ( "This won't be formatted either" ) - print ( "This won't be formatted either" )
- + elif NOT_IMPLEMENTED_left < NOT_IMPLEMENTED_right:
+ NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg)
- print("This will be formatted") - print("This will be formatted")
+NOT_YET_IMPLEMENTED_StmtClassDef + NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg)
# Regression test for https://github.com/psf/black/issues/2985. # Regression test for https://github.com/psf/black/issues/2985.
-class Named(t.Protocol): class Named(t.Protocol):
- # fmt: off # fmt: off
- @property @property
- def this_wont_be_formatted ( self ) -> str: ... - def this_wont_be_formatted ( self ) -> str: ...
+NOT_YET_IMPLEMENTED_StmtClassDef + def this_wont_be_formatted(self) -> str:
+ ...
-class Factory(t.Protocol): class Factory(t.Protocol):
- def this_will_be_formatted(self, **kwargs) -> Named: def this_will_be_formatted(self, **kwargs) -> Named:
- ... ...
- -
- # fmt: on # fmt: on
+NOT_YET_IMPLEMENTED_StmtClassDef
# Regression test for https://github.com/psf/black/issues/3436. @@ -82,6 +62,6 @@
if x: if x:
return x return x
# fmt: off # fmt: off
@ -231,14 +235,32 @@ else:
# Regression test for https://github.com/psf/black/issues/3184. # Regression test for https://github.com/psf/black/issues/3184.
NOT_YET_IMPLEMENTED_StmtClassDef class A:
async def call(param):
if param:
# fmt: off
if NOT_IMPLEMENTED_left < NOT_IMPLEMENTED_right:
# fmt: on
NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg)
elif NOT_IMPLEMENTED_left < NOT_IMPLEMENTED_right:
NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg)
NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg)
# Regression test for https://github.com/psf/black/issues/2985. # Regression test for https://github.com/psf/black/issues/2985.
NOT_YET_IMPLEMENTED_StmtClassDef class Named(t.Protocol):
# fmt: off
@property
def this_wont_be_formatted(self) -> str:
...
NOT_YET_IMPLEMENTED_StmtClassDef class Factory(t.Protocol):
def this_will_be_formatted(self, **kwargs) -> Named:
...
# fmt: on
# Regression test for https://github.com/psf/black/issues/3436. # Regression test for https://github.com/psf/black/issues/3436.

View File

@ -18,19 +18,23 @@ class A:
```diff ```diff
--- Black --- Black
+++ Ruff +++ Ruff
@@ -1,5 +1 @@ @@ -1,5 +1,5 @@
-class A: class A:
- def f(self): def f(self):
- for line in range(10): - for line in range(10):
- if True: + for line in NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg):
- pass # fmt: skip if True:
+NOT_YET_IMPLEMENTED_StmtClassDef pass # fmt: skip
``` ```
## Ruff Output ## Ruff Output
```py ```py
NOT_YET_IMPLEMENTED_StmtClassDef class A:
def f(self):
for line in NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg):
if True:
pass # fmt: skip
``` ```
## Black Output ## Black Output

View File

@ -75,7 +75,7 @@ async def test_async_with():
```diff ```diff
--- Black --- Black
+++ Ruff +++ Ruff
@@ -1,62 +1,47 @@ @@ -1,62 +1,54 @@
# Make sure a leading comment is not removed. # Make sure a leading comment is not removed.
-def some_func( unformatted, args ): # fmt: skip -def some_func( unformatted, args ): # fmt: skip
- print("I am some_func") - print("I am some_func")
@ -98,14 +98,19 @@ async def test_async_with():
-class SomeClass( Unformatted, SuperClasses ): # fmt: skip -class SomeClass( Unformatted, SuperClasses ): # fmt: skip
- def some_method( self, unformatted, args ): # fmt: skip - def some_method( self, unformatted, args ): # fmt: skip
- print("I am some_method") - print("I am some_method")
- return 0 +class SomeClass(Unformatted, SuperClasses): # fmt: skip
+NOT_YET_IMPLEMENTED_StmtClassDef + def some_method(self, unformatted, args): # fmt: skip
+ NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg)
return 0
- async def some_async_method( self, unformatted, args ): # fmt: skip - async def some_async_method( self, unformatted, args ): # fmt: skip
- print("I am some_async_method") - print("I am some_async_method")
- await asyncio.sleep(1) - await asyncio.sleep(1)
+ async def some_async_method(self, unformatted, args): # fmt: skip
+ NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg)
+ await NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg)
-
# Make sure a leading comment is not removed. # Make sure a leading comment is not removed.
-if unformatted_call( args ): # fmt: skip -if unformatted_call( args ): # fmt: skip
- print("First branch") - print("First branch")
@ -177,7 +182,14 @@ async def some_async_func(unformatted, args): # fmt: skip
# Make sure a leading comment is not removed. # Make sure a leading comment is not removed.
NOT_YET_IMPLEMENTED_StmtClassDef class SomeClass(Unformatted, SuperClasses): # fmt: skip
def some_method(self, unformatted, args): # fmt: skip
NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg)
return 0
async def some_async_method(self, unformatted, args): # fmt: skip
NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg)
await NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg)
# Make sure a leading comment is not removed. # Make sure a leading comment is not removed.

View File

@ -66,7 +66,7 @@ with hmm_but_this_should_get_two_preceding_newlines():
```diff ```diff
--- Black --- Black
+++ Ruff +++ Ruff
@@ -2,64 +2,39 @@ @@ -2,64 +2,41 @@
a, a,
**kwargs, **kwargs,
) -> A: ) -> A:
@ -129,17 +129,17 @@ with hmm_but_this_should_get_two_preceding_newlines():
elif False: elif False:
- -
- class IHopeYouAreHavingALovelyDay: class IHopeYouAreHavingALovelyDay:
- def __call__(self): def __call__(self):
- print("i_should_be_followed_by_only_one_newline") - print("i_should_be_followed_by_only_one_newline")
- -
+ NOT_YET_IMPLEMENTED_StmtClassDef + NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg)
else: else:
- -
def foo(): def foo():
pass pass
- -
-with hmm_but_this_should_get_two_preceding_newlines(): -with hmm_but_this_should_get_two_preceding_newlines():
- pass - pass
+NOT_YET_IMPLEMENTED_StmtWith +NOT_YET_IMPLEMENTED_StmtWith
@ -182,7 +182,9 @@ elif NOT_IMPLEMENTED_left < NOT_IMPLEMENTED_right:
NOT_YET_IMPLEMENTED_StmtTry NOT_YET_IMPLEMENTED_StmtTry
elif False: elif False:
NOT_YET_IMPLEMENTED_StmtClassDef class IHopeYouAreHavingALovelyDay:
def __call__(self):
NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg)
else: else:
def foo(): def foo():
pass pass

View File

@ -121,7 +121,7 @@ with open("/path/to/file.txt", mode="r") as read_file:
```diff ```diff
--- Black --- Black
+++ Ruff +++ Ruff
@@ -1,78 +1,72 @@ @@ -1,78 +1,74 @@
-import random -import random
+NOT_YET_IMPLEMENTED_StmtImport +NOT_YET_IMPLEMENTED_StmtImport
@ -151,10 +151,10 @@ with open("/path/to/file.txt", mode="r") as read_file:
+ NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg) + NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg)
-class Foo: class Foo:
- def bar(self): def bar(self):
- print("The newline above me should be deleted!") - print("The newline above me should be deleted!")
+NOT_YET_IMPLEMENTED_StmtClassDef + NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg)
-for i in range(5): -for i in range(5):
@ -255,7 +255,9 @@ def foo4():
NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg) NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg)
NOT_YET_IMPLEMENTED_StmtClassDef class Foo:
def bar(self):
NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg)
for i in NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg): for i in NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg):

View File

@ -42,7 +42,7 @@ assert (
```diff ```diff
--- Black --- Black
+++ Ruff +++ Ruff
@@ -2,57 +2,24 @@ @@ -2,20 +2,10 @@
( (
() ()
<< 0 << 0
@ -65,16 +65,16 @@ assert (
importA importA
0 0
0 ^ 0 # @@ -24,35 +14,15 @@
class A:
-class A: def foo(self):
- def foo(self):
- for _ in range(10): - for _ in range(10):
- aaaaaaaaaaaaaaaaaaa = bbbbbbbbbbbbbbb.cccccccccc( - aaaaaaaaaaaaaaaaaaa = bbbbbbbbbbbbbbb.cccccccccc(
- xxxxxxxxxxxx - xxxxxxxxxxxx
- ) # pylint: disable=no-member - ) # pylint: disable=no-member
+NOT_YET_IMPLEMENTED_StmtClassDef + for _ in NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg):
+ aaaaaaaaaaaaaaaaaaa = NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg)
def test(self, othr): def test(self, othr):
@ -126,7 +126,10 @@ importA
0 ^ 0 # 0 ^ 0 #
NOT_YET_IMPLEMENTED_StmtClassDef class A:
def foo(self):
for _ in NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg):
aaaaaaaaaaaaaaaaaaa = NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg)
def test(self, othr): def test(self, othr):

View File

@ -38,7 +38,7 @@ class A:
```diff ```diff
--- Black --- Black
+++ Ruff +++ Ruff
@@ -1,34 +1,15 @@ @@ -1,34 +1,25 @@
-if e1234123412341234.winerror not in ( -if e1234123412341234.winerror not in (
- _winapi.ERROR_SEM_TIMEOUT, - _winapi.ERROR_SEM_TIMEOUT,
- _winapi.ERROR_PIPE_BUSY, - _winapi.ERROR_PIPE_BUSY,
@ -61,25 +61,30 @@ class A:
+ new_id = NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg) + 1 + new_id = NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg) + 1
-class X: class X:
- def get_help_text(self): def get_help_text(self):
- return ngettext( - return ngettext(
- "Your password must contain at least %(min_length)d character.", - "Your password must contain at least %(min_length)d character.",
- "Your password must contain at least %(min_length)d characters.", - "Your password must contain at least %(min_length)d characters.",
- self.min_length, - self.min_length,
- ) % {"min_length": self.min_length} - ) % {"min_length": self.min_length}
+NOT_YET_IMPLEMENTED_StmtClassDef + return NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg) % {
+ "NOT_YET_IMPLEMENTED_STRING": self.min_length,
+ }
-class A: class A:
- def b(self): def b(self):
- if self.connection.mysql_is_mariadb and ( - if self.connection.mysql_is_mariadb and (
- 10, - 10,
- 4, - 4,
- 3, - 3,
- ) < self.connection.mysql_version < (10, 5, 2): - ) < self.connection.mysql_version < (10, 5, 2):
- pass + if (
+NOT_YET_IMPLEMENTED_StmtClassDef + self.connection.mysql_is_mariadb
+ and NOT_IMPLEMENTED_left < NOT_IMPLEMENTED_right
+ ):
pass
``` ```
## Ruff Output ## Ruff Output
@ -96,10 +101,20 @@ if x:
new_id = NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg) + 1 new_id = NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg) + 1
NOT_YET_IMPLEMENTED_StmtClassDef class X:
def get_help_text(self):
return NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg) % {
"NOT_YET_IMPLEMENTED_STRING": self.min_length,
}
NOT_YET_IMPLEMENTED_StmtClassDef class A:
def b(self):
if (
self.connection.mysql_is_mariadb
and NOT_IMPLEMENTED_left < NOT_IMPLEMENTED_right
):
pass
``` ```
## Black Output ## Black Output

View File

@ -0,0 +1,97 @@
---
source: crates/ruff_python_formatter/src/lib.rs
expression: snapshot
---
## Input
```py
class Test(
Aaaaaaaaaaaaaaaaa,
Bbbbbbbbbbbbbbbb,
DDDDDDDDDDDDDDDD,
EEEEEEEEEEEEEE,
metaclass=meta,
):
pass
class Test((Aaaaaaaaaaaaaaaaa), Bbbbbbbbbbbbbbbb, metaclass=meta):
pass
class Test( # trailing class comment
Aaaaaaaaaaaaaaaaa, # trailing comment
# in between comment
Bbbbbbbbbbbbbbbb,
# another leading comment
DDDDDDDDDDDDDDDD,
EEEEEEEEEEEEEE,
# meta comment
metaclass=meta, # trailing meta comment
):
pass
class Test((Aaaa)):
...
class Test(aaaaaaaaaaaaaaa + bbbbbbbbbbbbbbbbbbbbbb + cccccccccccccccccccccccc + dddddddddddddddddddddd + eeeeeeeee, ffffffffffffffffff, gggggggggggggggggg):
pass
class Test(Aaaa): # trailing comment
pass
```
## Output
```py
class Test(
Aaaaaaaaaaaaaaaaa,
Bbbbbbbbbbbbbbbb,
DDDDDDDDDDDDDDDD,
EEEEEEEEEEEEEE,
metaclass=meta,
):
pass
class Test((Aaaaaaaaaaaaaaaaa), Bbbbbbbbbbbbbbbb, metaclass=meta):
pass
class Test(
# trailing class comment
Aaaaaaaaaaaaaaaaa, # trailing comment
# in between comment
Bbbbbbbbbbbbbbbb,
# another leading comment
DDDDDDDDDDDDDDDD,
EEEEEEEEEEEEEE,
# meta comment
metaclass=meta, # trailing meta comment
):
pass
class Test((Aaaa)):
...
class Test(
aaaaaaaaaaaaaaa
+ bbbbbbbbbbbbbbbbbbbbbb
+ cccccccccccccccccccccccc
+ dddddddddddddddddddddd
+ eeeeeeeee,
ffffffffffffffffff,
gggggggggggggggggg,
):
pass
class Test(Aaaa): # trailing comment
pass
```

View File

@ -52,7 +52,10 @@ b = 20
# Adds two lines after `b` # Adds two lines after `b`
NOT_YET_IMPLEMENTED_StmtClassDef class Test:
def a(self):
pass
# trailing comment
# two lines before, one line after # two lines before, one line after

View File

@ -1,12 +1,138 @@
use crate::{not_yet_implemented, FormatNodeRule, PyFormatter}; use crate::comments::trailing_comments;
use ruff_formatter::{write, Buffer, FormatResult}; use crate::expression::parentheses::Parenthesize;
use rustpython_parser::ast::StmtClassDef; use crate::prelude::*;
use crate::trivia::{first_non_trivia_token, SimpleTokenizer, Token, TokenKind};
use crate::USE_MAGIC_TRAILING_COMMA;
use ruff_formatter::{format_args, write};
use ruff_text_size::TextRange;
use rustpython_parser::ast::{Expr, Keyword, Ranged, StmtClassDef};
#[derive(Default)] #[derive(Default)]
pub struct FormatStmtClassDef; pub struct FormatStmtClassDef;
impl FormatNodeRule<StmtClassDef> for FormatStmtClassDef { impl FormatNodeRule<StmtClassDef> for FormatStmtClassDef {
fn fmt_fields(&self, item: &StmtClassDef, f: &mut PyFormatter) -> FormatResult<()> { fn fmt_fields(&self, item: &StmtClassDef, f: &mut PyFormatter) -> FormatResult<()> {
write!(f, [not_yet_implemented(item)]) let StmtClassDef {
range: _,
name,
bases,
keywords,
body,
decorator_list,
} = item;
f.join_with(hard_line_break())
.entries(decorator_list.iter().formatted())
.finish()?;
if !decorator_list.is_empty() {
hard_line_break().fmt(f)?;
}
write!(f, [text("class"), space(), name.format()])?;
if !(bases.is_empty() && keywords.is_empty()) {
write!(
f,
[group(&format_args![
text("("),
soft_block_indent(&FormatInheritanceClause {
class_definition: item
}),
text(")")
])]
)?;
}
let comments = f.context().comments().clone();
let trailing_head_comments = comments.dangling_comments(item);
write!(
f,
[
text(":"),
trailing_comments(trailing_head_comments),
block_indent(&body.format())
]
)
}
fn fmt_dangling_comments(
&self,
_node: &StmtClassDef,
_f: &mut PyFormatter,
) -> FormatResult<()> {
// handled in fmt_fields
Ok(())
}
}
struct FormatInheritanceClause<'a> {
class_definition: &'a StmtClassDef,
}
impl Format<PyFormatContext<'_>> for FormatInheritanceClause<'_> {
fn fmt(&self, f: &mut Formatter<PyFormatContext<'_>>) -> FormatResult<()> {
let StmtClassDef {
bases,
keywords,
name,
..
} = self.class_definition;
let separator = format_with(|f| write!(f, [text(","), soft_line_break_or_space()]));
let source = f.context().contents();
let mut joiner = f.join_with(&separator);
if let Some((first, rest)) = bases.split_first() {
// Manually handle parentheses for the first expression because the logic in `FormatExpr`
// doesn't know that it should disregard the parentheses of the inheritance clause.
// ```python
// class Test(A) # A is not parenthesized, the parentheses belong to the inheritance clause
// class Test((A)) # A is parenthesized
// ```
// parentheses from the inheritance clause belong to the expression.
let tokenizer = SimpleTokenizer::new(source, TextRange::new(name.end(), first.start()))
.skip_trivia();
let left_paren_count = tokenizer
.take_while(|token| token.kind() == TokenKind::LParen)
.count();
// Ignore the first parentheses count
let parenthesize = if left_paren_count > 1 {
Parenthesize::Always
} else {
Parenthesize::Never
};
joiner.entry(&first.format().with_options(parenthesize));
joiner.entries(rest.iter().formatted());
}
joiner.entries(keywords.iter().formatted()).finish()?;
if_group_breaks(&text(",")).fmt(f)?;
if USE_MAGIC_TRAILING_COMMA {
let last_end = keywords
.last()
.map(Keyword::end)
.or_else(|| bases.last().map(Expr::end))
.unwrap();
if matches!(
first_non_trivia_token(last_end, f.context().contents()),
Some(Token {
kind: TokenKind::Comma,
..
})
) {
hard_line_break().fmt(f)?;
}
}
Ok(())
} }
} }

View File

@ -252,7 +252,8 @@ one_leading_newline = 10
no_leading_newline = 30 no_leading_newline = 30
NOT_YET_IMPLEMENTED_StmtClassDef class InTheMiddle:
pass
trailing_statement = 1 trailing_statement = 1
@ -283,7 +284,8 @@ two_leading_newlines = 20
one_leading_newline = 10 one_leading_newline = 10
no_leading_newline = 30 no_leading_newline = 30
NOT_YET_IMPLEMENTED_StmtClassDef class InTheMiddle:
pass
trailing_statement = 1 trailing_statement = 1