mirror of
https://github.com/astral-sh/ruff.git
synced 2025-07-23 04:55:09 +00:00
Add support for basic Constant::Str
formatting (#3173)
This PR enables us to apply the proper quotation marks, including support for escapes. There are some significant TODOs, especially around implicit concatenations like: ```py ( "abc" "def" ) ``` Which are represented as a single AST node, which requires us to tokenize _within_ the formatter to identify all the individual string parts.
This commit is contained in:
parent
095f005bf4
commit
f967f344fc
24 changed files with 426 additions and 706 deletions
23
crates/ruff_python_formatter/src/core/helpers.rs
Normal file
23
crates/ruff_python_formatter/src/core/helpers.rs
Normal file
|
@ -0,0 +1,23 @@
|
|||
use ruff_python::string::{
|
||||
SINGLE_QUOTE_PREFIXES, SINGLE_QUOTE_SUFFIXES, TRIPLE_QUOTE_PREFIXES, TRIPLE_QUOTE_SUFFIXES,
|
||||
};
|
||||
|
||||
/// Return the leading quote string for a docstring (e.g., `"""`).
|
||||
pub fn leading_quote(content: &str) -> Option<&str> {
|
||||
if let Some(first_line) = content.lines().next() {
|
||||
for pattern in TRIPLE_QUOTE_PREFIXES.iter().chain(SINGLE_QUOTE_PREFIXES) {
|
||||
if first_line.starts_with(pattern) {
|
||||
return Some(pattern);
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
/// Return the trailing quote string for a docstring (e.g., `"""`).
|
||||
pub fn trailing_quote(content: &str) -> Option<&&str> {
|
||||
TRIPLE_QUOTE_SUFFIXES
|
||||
.iter()
|
||||
.chain(SINGLE_QUOTE_SUFFIXES)
|
||||
.find(|&pattern| content.ends_with(pattern))
|
||||
}
|
|
@ -1,3 +1,4 @@
|
|||
pub mod helpers;
|
||||
pub mod locator;
|
||||
pub mod types;
|
||||
pub mod visitor;
|
||||
|
|
|
@ -13,6 +13,7 @@ use crate::cst::{
|
|||
Arguments, Boolop, Cmpop, Comprehension, Expr, ExprKind, Keyword, Operator, Unaryop,
|
||||
};
|
||||
use crate::format::helpers::{is_self_closing, is_simple_power, is_simple_slice};
|
||||
use crate::format::strings::string_literal;
|
||||
use crate::shared_traits::AsFormat;
|
||||
use crate::trivia::{Parenthesize, Relationship, TriviaKind};
|
||||
|
||||
|
@ -128,8 +129,6 @@ fn format_tuple(
|
|||
write!(
|
||||
f,
|
||||
[soft_block_indent(&format_with(|f| {
|
||||
// TODO(charlie): If the magic trailing comma isn't present, and the
|
||||
// tuple is _already_ expanded, we're not supposed to add this.
|
||||
let magic_trailing_comma = expr
|
||||
.trivia
|
||||
.iter()
|
||||
|
@ -641,10 +640,21 @@ fn format_joined_str(
|
|||
fn format_constant(
|
||||
f: &mut Formatter<ASTFormatContext<'_>>,
|
||||
expr: &Expr,
|
||||
_constant: &Constant,
|
||||
constant: &Constant,
|
||||
_kind: Option<&str>,
|
||||
) -> FormatResult<()> {
|
||||
write!(f, [literal(Range::from_located(expr))])?;
|
||||
match constant {
|
||||
Constant::None => write!(f, [text("None")])?,
|
||||
Constant::Bool(value) => {
|
||||
if *value {
|
||||
write!(f, [text("True")])?;
|
||||
} else {
|
||||
write!(f, [text("False")])?;
|
||||
}
|
||||
}
|
||||
Constant::Str(_) => write!(f, [string_literal(expr)])?,
|
||||
_ => write!(f, [literal(Range::from_located(expr))])?,
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
|
@ -10,5 +10,6 @@ mod expr;
|
|||
mod helpers;
|
||||
mod operator;
|
||||
mod stmt;
|
||||
mod strings;
|
||||
mod unaryop;
|
||||
mod withitem;
|
||||
|
|
240
crates/ruff_python_formatter/src/format/strings.rs
Normal file
240
crates/ruff_python_formatter/src/format/strings.rs
Normal file
|
@ -0,0 +1,240 @@
|
|||
use rustpython_parser::{Mode, Tok};
|
||||
|
||||
use ruff_formatter::prelude::*;
|
||||
use ruff_formatter::{write, Format};
|
||||
use ruff_text_size::TextSize;
|
||||
|
||||
use crate::context::ASTFormatContext;
|
||||
use crate::core::helpers::{leading_quote, trailing_quote};
|
||||
use crate::core::types::Range;
|
||||
use crate::cst::Expr;
|
||||
use crate::trivia::Parenthesize;
|
||||
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||
pub struct StringLiteralPart {
|
||||
range: Range,
|
||||
}
|
||||
|
||||
impl Format<ASTFormatContext<'_>> for StringLiteralPart {
|
||||
fn fmt(&self, f: &mut Formatter<ASTFormatContext<'_>>) -> FormatResult<()> {
|
||||
let (source, start, end) = f.context().locator().slice(self.range);
|
||||
|
||||
// Extract leading and trailing quotes.
|
||||
let content = &source[start..end];
|
||||
let leading_quote = leading_quote(content).unwrap();
|
||||
let trailing_quote = trailing_quote(content).unwrap();
|
||||
let body = &content[leading_quote.len()..content.len() - trailing_quote.len()];
|
||||
|
||||
// Determine the correct quote style.
|
||||
// TODO(charlie): Make this parameterizable.
|
||||
let mut squotes: usize = 0;
|
||||
let mut dquotes: usize = 0;
|
||||
for char in body.chars() {
|
||||
if char == '\'' {
|
||||
squotes += 1;
|
||||
} else if char == '"' {
|
||||
dquotes += 1;
|
||||
}
|
||||
}
|
||||
|
||||
let mut is_raw = false;
|
||||
if leading_quote.contains('r') {
|
||||
is_raw = true;
|
||||
f.write_element(FormatElement::StaticText { text: "r" })?;
|
||||
} else if leading_quote.contains('R') {
|
||||
is_raw = true;
|
||||
f.write_element(FormatElement::StaticText { text: "R" })?;
|
||||
}
|
||||
|
||||
if trailing_quote.len() == 1 {
|
||||
// Single-quoted string.
|
||||
if dquotes == 0 || squotes > 0 {
|
||||
// If the body doesn't contain any double quotes, or it contains both single and
|
||||
// double quotes, use double quotes.
|
||||
f.write_element(FormatElement::StaticText { text: "\"" })?;
|
||||
f.write_element(FormatElement::DynamicText {
|
||||
text: if is_raw {
|
||||
body.into()
|
||||
} else {
|
||||
double_escape(body).into()
|
||||
},
|
||||
source_position: TextSize::default(),
|
||||
})?;
|
||||
f.write_element(FormatElement::StaticText { text: "\"" })?;
|
||||
Ok(())
|
||||
} else {
|
||||
f.write_element(FormatElement::StaticText { text: "'" })?;
|
||||
f.write_element(FormatElement::DynamicText {
|
||||
text: if is_raw {
|
||||
body.into()
|
||||
} else {
|
||||
single_escape(body).into()
|
||||
},
|
||||
source_position: TextSize::default(),
|
||||
})?;
|
||||
f.write_element(FormatElement::StaticText { text: "'" })?;
|
||||
Ok(())
|
||||
}
|
||||
} else if trailing_quote.len() == 3 {
|
||||
// Triple-quoted string.
|
||||
if body.starts_with("\"\"\"") || body.ends_with('"') {
|
||||
// We only need to use single quotes if the string body starts with three or more
|
||||
// double quotes, or ends with a double quote. Converting to double quotes in those
|
||||
// cases would cause a syntax error.
|
||||
f.write_element(FormatElement::StaticText { text: "'''" })?;
|
||||
f.write_element(FormatElement::DynamicText {
|
||||
text: body.to_string().into_boxed_str(),
|
||||
source_position: TextSize::default(),
|
||||
})?;
|
||||
f.write_element(FormatElement::StaticText { text: "'''" })?;
|
||||
Ok(())
|
||||
} else {
|
||||
f.write_element(FormatElement::StaticText { text: "\"\"\"" })?;
|
||||
f.write_element(FormatElement::DynamicText {
|
||||
text: body.to_string().into_boxed_str(),
|
||||
source_position: TextSize::default(),
|
||||
})?;
|
||||
f.write_element(FormatElement::StaticText { text: "\"\"\"" })?;
|
||||
Ok(())
|
||||
}
|
||||
} else {
|
||||
unreachable!("Invalid quote length: {}", trailing_quote.len());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub const fn string_literal_part(range: Range) -> StringLiteralPart {
|
||||
StringLiteralPart { range }
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct StringLiteral<'a> {
|
||||
expr: &'a Expr,
|
||||
}
|
||||
|
||||
impl Format<ASTFormatContext<'_>> for StringLiteral<'_> {
|
||||
fn fmt(&self, f: &mut Formatter<ASTFormatContext<'_>>) -> FormatResult<()> {
|
||||
let expr = self.expr;
|
||||
|
||||
// TODO(charlie): This tokenization needs to happen earlier, so that we can attach
|
||||
// comments to individual string literals.
|
||||
let (source, start, end) = f.context().locator().slice(Range::from_located(expr));
|
||||
let elts =
|
||||
rustpython_parser::lexer::lex_located(&source[start..end], Mode::Module, expr.location)
|
||||
.flatten()
|
||||
.filter_map(|(start, tok, end)| {
|
||||
if matches!(tok, Tok::String { .. }) {
|
||||
Some(Range::new(start, end))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
write!(
|
||||
f,
|
||||
[group(&format_with(|f| {
|
||||
if matches!(expr.parentheses, Parenthesize::IfExpanded) {
|
||||
write!(f, [if_group_breaks(&text("("))])?;
|
||||
}
|
||||
for (i, elt) in elts.iter().enumerate() {
|
||||
write!(f, [string_literal_part(*elt)])?;
|
||||
if i < elts.len() - 1 {
|
||||
write!(f, [soft_line_break_or_space()])?;
|
||||
}
|
||||
}
|
||||
if matches!(expr.parentheses, Parenthesize::IfExpanded) {
|
||||
write!(f, [if_group_breaks(&text(")"))])?;
|
||||
}
|
||||
Ok(())
|
||||
}))]
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub const fn string_literal(expr: &Expr) -> StringLiteral {
|
||||
StringLiteral { expr }
|
||||
}
|
||||
|
||||
/// Escape a string body to be used in a string literal with double quotes.
|
||||
fn double_escape(text: &str) -> String {
|
||||
let mut escaped = String::with_capacity(text.len());
|
||||
let mut chars = text.chars().peekable();
|
||||
while let Some(ch) = chars.next() {
|
||||
if ch == '\\' {
|
||||
let Some(next) = chars.peek() else {
|
||||
break;
|
||||
};
|
||||
if *next == '\'' {
|
||||
chars.next();
|
||||
escaped.push('\'');
|
||||
} else if *next == '"' {
|
||||
chars.next();
|
||||
escaped.push('"');
|
||||
} else if *next == '\\' {
|
||||
chars.next();
|
||||
escaped.push('\\');
|
||||
escaped.push(ch);
|
||||
} else {
|
||||
escaped.push(ch);
|
||||
}
|
||||
} else if ch == '"' {
|
||||
escaped.push('\\');
|
||||
escaped.push('"');
|
||||
} else {
|
||||
escaped.push(ch);
|
||||
}
|
||||
}
|
||||
escaped
|
||||
}
|
||||
|
||||
/// Escape a string body to be used in a string literal with single quotes.
|
||||
fn single_escape(text: &str) -> String {
|
||||
let mut escaped = String::with_capacity(text.len());
|
||||
let mut chars = text.chars().peekable();
|
||||
while let Some(ch) = chars.next() {
|
||||
if ch == '\\' {
|
||||
let Some(next) = chars.peek() else {
|
||||
break;
|
||||
};
|
||||
if *next == '"' {
|
||||
chars.next();
|
||||
escaped.push('"');
|
||||
} else if *next == '\'' {
|
||||
chars.next();
|
||||
escaped.push('\'');
|
||||
} else if *next == '\\' {
|
||||
chars.next();
|
||||
escaped.push('\\');
|
||||
escaped.push(ch);
|
||||
} else {
|
||||
escaped.push(ch);
|
||||
}
|
||||
} else if ch == '\'' {
|
||||
escaped.push('\\');
|
||||
escaped.push('\'');
|
||||
} else {
|
||||
escaped.push(ch);
|
||||
}
|
||||
}
|
||||
escaped
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_double_escape() {
|
||||
assert_eq!(double_escape(r#"It\'s mine"#), r#"It's mine"#);
|
||||
assert_eq!(double_escape(r#"It\'s "mine""#), r#"It's \"mine\""#);
|
||||
assert_eq!(double_escape(r#"It\\'s mine"#), r#"It\\'s mine"#);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_single_escape() {
|
||||
assert_eq!(single_escape(r#"It's \"mine\""#), r#"It\'s "mine""#);
|
||||
}
|
||||
}
|
|
@ -1,49 +0,0 @@
|
|||
---
|
||||
source: crates/ruff_python_formatter/src/lib.rs
|
||||
expression: snapshot
|
||||
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/bracketmatch.py
|
||||
---
|
||||
## Input
|
||||
|
||||
```py
|
||||
for ((x in {}) or {})['a'] in x:
|
||||
pass
|
||||
pem_spam = lambda l, spam = {
|
||||
"x": 3
|
||||
}: not spam.get(l.strip())
|
||||
lambda x=lambda y={1: 3}: y['x':lambda y: {1: 2}]: x
|
||||
```
|
||||
|
||||
## Black Differences
|
||||
|
||||
```diff
|
||||
--- Black
|
||||
+++ Ruff
|
||||
@@ -1,4 +1,4 @@
|
||||
-for ((x in {}) or {})["a"] in x:
|
||||
+for ((x in {}) or {})['a'] in x:
|
||||
pass
|
||||
pem_spam = lambda l, spam={"x": 3}: not spam.get(l.strip())
|
||||
-lambda x=lambda y={1: 3}: y["x" : lambda y: {1: 2}]: x
|
||||
+lambda x=lambda y={1: 3}: y['x' : lambda y: {1: 2}]: x
|
||||
```
|
||||
|
||||
## Ruff Output
|
||||
|
||||
```py
|
||||
for ((x in {}) or {})['a'] in x:
|
||||
pass
|
||||
pem_spam = lambda l, spam={"x": 3}: not spam.get(l.strip())
|
||||
lambda x=lambda y={1: 3}: y['x' : lambda y: {1: 2}]: x
|
||||
```
|
||||
|
||||
## Black Output
|
||||
|
||||
```py
|
||||
for ((x in {}) or {})["a"] in x:
|
||||
pass
|
||||
pem_spam = lambda l, spam={"x": 3}: not spam.get(l.strip())
|
||||
lambda x=lambda y={1: 3}: y["x" : lambda y: {1: 2}]: x
|
||||
```
|
||||
|
||||
|
|
@ -1,319 +0,0 @@
|
|||
---
|
||||
source: crates/ruff_python_formatter/src/lib.rs
|
||||
expression: snapshot
|
||||
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/collections.py
|
||||
---
|
||||
## Input
|
||||
|
||||
```py
|
||||
import core, time, a
|
||||
|
||||
from . import A, B, C
|
||||
|
||||
# keeps existing trailing comma
|
||||
from foo import (
|
||||
bar,
|
||||
)
|
||||
|
||||
# also keeps existing structure
|
||||
from foo import (
|
||||
baz,
|
||||
qux,
|
||||
)
|
||||
|
||||
# `as` works as well
|
||||
from foo import (
|
||||
xyzzy as magic,
|
||||
)
|
||||
|
||||
a = {1,2,3,}
|
||||
b = {
|
||||
1,2,
|
||||
3}
|
||||
c = {
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
}
|
||||
x = 1,
|
||||
y = narf(),
|
||||
nested = {(1,2,3),(4,5,6),}
|
||||
nested_no_trailing_comma = {(1,2,3),(4,5,6)}
|
||||
nested_long_lines = ["aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", "cccccccccccccccccccccccccccccccccccccccc", (1, 2, 3), "dddddddddddddddddddddddddddddddddddddddd"]
|
||||
{"oneple": (1,),}
|
||||
{"oneple": (1,)}
|
||||
['ls', 'lsoneple/%s' % (foo,)]
|
||||
x = {"oneple": (1,)}
|
||||
y = {"oneple": (1,),}
|
||||
assert False, ("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa wraps %s" % bar)
|
||||
|
||||
# looping over a 1-tuple should also not get wrapped
|
||||
for x in (1,):
|
||||
pass
|
||||
for (x,) in (1,), (2,), (3,):
|
||||
pass
|
||||
|
||||
[1, 2, 3,]
|
||||
|
||||
division_result_tuple = (6/2,)
|
||||
print("foo %r", (foo.bar,))
|
||||
|
||||
if True:
|
||||
IGNORED_TYPES_FOR_ATTRIBUTE_CHECKING = (
|
||||
Config.IGNORED_TYPES_FOR_ATTRIBUTE_CHECKING
|
||||
| {pylons.controllers.WSGIController}
|
||||
)
|
||||
|
||||
if True:
|
||||
ec2client.get_waiter('instance_stopped').wait(
|
||||
InstanceIds=[instance.id],
|
||||
WaiterConfig={
|
||||
'Delay': 5,
|
||||
})
|
||||
ec2client.get_waiter("instance_stopped").wait(
|
||||
InstanceIds=[instance.id],
|
||||
WaiterConfig={"Delay": 5,},
|
||||
)
|
||||
ec2client.get_waiter("instance_stopped").wait(
|
||||
InstanceIds=[instance.id], WaiterConfig={"Delay": 5,},
|
||||
)
|
||||
```
|
||||
|
||||
## Black Differences
|
||||
|
||||
```diff
|
||||
--- Black
|
||||
+++ Ruff
|
||||
@@ -47,7 +47,7 @@
|
||||
"oneple": (1,),
|
||||
}
|
||||
{"oneple": (1,)}
|
||||
-["ls", "lsoneple/%s" % (foo,)]
|
||||
+['ls', 'lsoneple/%s' % (foo,)]
|
||||
x = {"oneple": (1,)}
|
||||
y = {
|
||||
"oneple": (1,),
|
||||
@@ -79,10 +79,10 @@
|
||||
)
|
||||
|
||||
if True:
|
||||
- ec2client.get_waiter("instance_stopped").wait(
|
||||
+ ec2client.get_waiter('instance_stopped').wait(
|
||||
InstanceIds=[instance.id],
|
||||
WaiterConfig={
|
||||
- "Delay": 5,
|
||||
+ 'Delay': 5,
|
||||
},
|
||||
)
|
||||
ec2client.get_waiter("instance_stopped").wait(
|
||||
```
|
||||
|
||||
## Ruff Output
|
||||
|
||||
```py
|
||||
import core, time, a
|
||||
|
||||
from . import A, B, C
|
||||
|
||||
# keeps existing trailing comma
|
||||
from foo import (
|
||||
bar,
|
||||
)
|
||||
|
||||
# also keeps existing structure
|
||||
from foo import (
|
||||
baz,
|
||||
qux,
|
||||
)
|
||||
|
||||
# `as` works as well
|
||||
from foo import (
|
||||
xyzzy as magic,
|
||||
)
|
||||
|
||||
a = {
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
}
|
||||
b = {1, 2, 3}
|
||||
c = {
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
}
|
||||
x = (1,)
|
||||
y = (narf(),)
|
||||
nested = {
|
||||
(1, 2, 3),
|
||||
(4, 5, 6),
|
||||
}
|
||||
nested_no_trailing_comma = {(1, 2, 3), (4, 5, 6)}
|
||||
nested_long_lines = [
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
||||
"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
|
||||
"cccccccccccccccccccccccccccccccccccccccc",
|
||||
(1, 2, 3),
|
||||
"dddddddddddddddddddddddddddddddddddddddd",
|
||||
]
|
||||
{
|
||||
"oneple": (1,),
|
||||
}
|
||||
{"oneple": (1,)}
|
||||
['ls', 'lsoneple/%s' % (foo,)]
|
||||
x = {"oneple": (1,)}
|
||||
y = {
|
||||
"oneple": (1,),
|
||||
}
|
||||
assert False, (
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa wraps %s"
|
||||
% bar
|
||||
)
|
||||
|
||||
# looping over a 1-tuple should also not get wrapped
|
||||
for x in (1,):
|
||||
pass
|
||||
for (x,) in (1,), (2,), (3,):
|
||||
pass
|
||||
|
||||
[
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
]
|
||||
|
||||
division_result_tuple = (6 / 2,)
|
||||
print("foo %r", (foo.bar,))
|
||||
|
||||
if True:
|
||||
IGNORED_TYPES_FOR_ATTRIBUTE_CHECKING = (
|
||||
Config.IGNORED_TYPES_FOR_ATTRIBUTE_CHECKING
|
||||
| {pylons.controllers.WSGIController}
|
||||
)
|
||||
|
||||
if True:
|
||||
ec2client.get_waiter('instance_stopped').wait(
|
||||
InstanceIds=[instance.id],
|
||||
WaiterConfig={
|
||||
'Delay': 5,
|
||||
},
|
||||
)
|
||||
ec2client.get_waiter("instance_stopped").wait(
|
||||
InstanceIds=[instance.id],
|
||||
WaiterConfig={
|
||||
"Delay": 5,
|
||||
},
|
||||
)
|
||||
ec2client.get_waiter("instance_stopped").wait(
|
||||
InstanceIds=[instance.id],
|
||||
WaiterConfig={
|
||||
"Delay": 5,
|
||||
},
|
||||
)
|
||||
```
|
||||
|
||||
## Black Output
|
||||
|
||||
```py
|
||||
import core, time, a
|
||||
|
||||
from . import A, B, C
|
||||
|
||||
# keeps existing trailing comma
|
||||
from foo import (
|
||||
bar,
|
||||
)
|
||||
|
||||
# also keeps existing structure
|
||||
from foo import (
|
||||
baz,
|
||||
qux,
|
||||
)
|
||||
|
||||
# `as` works as well
|
||||
from foo import (
|
||||
xyzzy as magic,
|
||||
)
|
||||
|
||||
a = {
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
}
|
||||
b = {1, 2, 3}
|
||||
c = {
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
}
|
||||
x = (1,)
|
||||
y = (narf(),)
|
||||
nested = {
|
||||
(1, 2, 3),
|
||||
(4, 5, 6),
|
||||
}
|
||||
nested_no_trailing_comma = {(1, 2, 3), (4, 5, 6)}
|
||||
nested_long_lines = [
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
||||
"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
|
||||
"cccccccccccccccccccccccccccccccccccccccc",
|
||||
(1, 2, 3),
|
||||
"dddddddddddddddddddddddddddddddddddddddd",
|
||||
]
|
||||
{
|
||||
"oneple": (1,),
|
||||
}
|
||||
{"oneple": (1,)}
|
||||
["ls", "lsoneple/%s" % (foo,)]
|
||||
x = {"oneple": (1,)}
|
||||
y = {
|
||||
"oneple": (1,),
|
||||
}
|
||||
assert False, (
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa wraps %s"
|
||||
% bar
|
||||
)
|
||||
|
||||
# looping over a 1-tuple should also not get wrapped
|
||||
for x in (1,):
|
||||
pass
|
||||
for (x,) in (1,), (2,), (3,):
|
||||
pass
|
||||
|
||||
[
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
]
|
||||
|
||||
division_result_tuple = (6 / 2,)
|
||||
print("foo %r", (foo.bar,))
|
||||
|
||||
if True:
|
||||
IGNORED_TYPES_FOR_ATTRIBUTE_CHECKING = (
|
||||
Config.IGNORED_TYPES_FOR_ATTRIBUTE_CHECKING
|
||||
| {pylons.controllers.WSGIController}
|
||||
)
|
||||
|
||||
if True:
|
||||
ec2client.get_waiter("instance_stopped").wait(
|
||||
InstanceIds=[instance.id],
|
||||
WaiterConfig={
|
||||
"Delay": 5,
|
||||
},
|
||||
)
|
||||
ec2client.get_waiter("instance_stopped").wait(
|
||||
InstanceIds=[instance.id],
|
||||
WaiterConfig={
|
||||
"Delay": 5,
|
||||
},
|
||||
)
|
||||
ec2client.get_waiter("instance_stopped").wait(
|
||||
InstanceIds=[instance.id],
|
||||
WaiterConfig={
|
||||
"Delay": 5,
|
||||
},
|
||||
)
|
||||
```
|
||||
|
||||
|
|
@ -178,7 +178,7 @@ instruction()#comment with bad spacing
|
|||
```diff
|
||||
--- Black
|
||||
+++ Ruff
|
||||
@@ -1,31 +1,31 @@
|
||||
@@ -1,8 +1,8 @@
|
||||
from com.my_lovely_company.my_lovely_team.my_lovely_project.my_lovely_component import (
|
||||
- MyLovelyCompanyTeamProjectComponent, # NOT DRY
|
||||
+ MyLovelyCompanyTeamProjectComponent,
|
||||
|
@ -189,52 +189,25 @@ instruction()#comment with bad spacing
|
|||
)
|
||||
|
||||
# Please keep __all__ alphabetized within each category.
|
||||
|
||||
__all__ = [
|
||||
# Super-special typing primitives.
|
||||
- "Any",
|
||||
- "Callable",
|
||||
- "ClassVar",
|
||||
+ 'Any',
|
||||
+ 'Callable',
|
||||
+ 'ClassVar',
|
||||
@@ -13,7 +13,7 @@
|
||||
"Callable",
|
||||
"ClassVar",
|
||||
# ABCs (from collections.abc).
|
||||
- "AbstractSet", # collections.abc.Set.
|
||||
- "ByteString",
|
||||
- "Container",
|
||||
+ 'AbstractSet',
|
||||
+ 'ByteString',
|
||||
+ 'Container',
|
||||
+ "AbstractSet",
|
||||
"ByteString",
|
||||
"Container",
|
||||
# Concrete collection types.
|
||||
- "Counter",
|
||||
- "Deque",
|
||||
- "Dict",
|
||||
- "DefaultDict",
|
||||
- "List",
|
||||
- "Set",
|
||||
- "FrozenSet",
|
||||
@@ -24,7 +24,7 @@
|
||||
"List",
|
||||
"Set",
|
||||
"FrozenSet",
|
||||
- "NamedTuple", # Not really a type.
|
||||
- "Generator",
|
||||
+ 'Counter',
|
||||
+ 'Deque',
|
||||
+ 'Dict',
|
||||
+ 'DefaultDict',
|
||||
+ 'List',
|
||||
+ 'Set',
|
||||
+ 'FrozenSet',
|
||||
+ 'NamedTuple',
|
||||
+ 'Generator',
|
||||
+ "NamedTuple",
|
||||
"Generator",
|
||||
]
|
||||
|
||||
not_shareables = [
|
||||
@@ -48,38 +48,45 @@
|
||||
SubBytes(b"spam"),
|
||||
]
|
||||
|
||||
-if "PYTHON" in os.environ:
|
||||
+if 'PYTHON' in os.environ:
|
||||
add_compiler(compiler_from_env())
|
||||
else:
|
||||
@@ -54,32 +54,39 @@
|
||||
# for compiler in compilers.values():
|
||||
# add_compiler(compiler)
|
||||
add_compiler(compilers[(7.0, 32)])
|
||||
|
@ -284,7 +257,7 @@ instruction()#comment with bad spacing
|
|||
):
|
||||
pass
|
||||
# no newline before or after
|
||||
@@ -103,47 +110,47 @@
|
||||
@@ -103,42 +110,42 @@
|
||||
############################################################################
|
||||
|
||||
call2(
|
||||
|
@ -323,12 +296,11 @@ instruction()#comment with bad spacing
|
|||
]
|
||||
lcomp3 = [
|
||||
# This one is actually too long to fit in a single line.
|
||||
- element.split("\n", 1)[0]
|
||||
element.split("\n", 1)[0]
|
||||
- # yup
|
||||
- for element in collection.select_elements()
|
||||
- # right
|
||||
- if element is not None
|
||||
+ element.split('\n', 1)[0]
|
||||
+ for # yup
|
||||
+ element in collection.select_elements()
|
||||
+ if # right
|
||||
|
@ -346,12 +318,6 @@ instruction()#comment with bad spacing
|
|||
|
||||
# let's return
|
||||
return Node(
|
||||
syms.simple_stmt,
|
||||
- [Node(statement, result), Leaf(token.NEWLINE, "\n")], # FIXME: \r\n?
|
||||
+ [Node(statement, result), Leaf(token.NEWLINE, '\n')], # FIXME: \r\n?
|
||||
)
|
||||
|
||||
|
||||
@@ -167,7 +174,7 @@
|
||||
#######################
|
||||
|
||||
|
@ -377,23 +343,23 @@ from com.my_lovely_company.my_lovely_team.my_lovely_project.my_lovely_component
|
|||
|
||||
__all__ = [
|
||||
# Super-special typing primitives.
|
||||
'Any',
|
||||
'Callable',
|
||||
'ClassVar',
|
||||
"Any",
|
||||
"Callable",
|
||||
"ClassVar",
|
||||
# ABCs (from collections.abc).
|
||||
'AbstractSet',
|
||||
'ByteString',
|
||||
'Container',
|
||||
"AbstractSet",
|
||||
"ByteString",
|
||||
"Container",
|
||||
# Concrete collection types.
|
||||
'Counter',
|
||||
'Deque',
|
||||
'Dict',
|
||||
'DefaultDict',
|
||||
'List',
|
||||
'Set',
|
||||
'FrozenSet',
|
||||
'NamedTuple',
|
||||
'Generator',
|
||||
"Counter",
|
||||
"Deque",
|
||||
"Dict",
|
||||
"DefaultDict",
|
||||
"List",
|
||||
"Set",
|
||||
"FrozenSet",
|
||||
"NamedTuple",
|
||||
"Generator",
|
||||
]
|
||||
|
||||
not_shareables = [
|
||||
|
@ -416,7 +382,7 @@ not_shareables = [
|
|||
SubBytes(b"spam"),
|
||||
]
|
||||
|
||||
if 'PYTHON' in os.environ:
|
||||
if "PYTHON" in os.environ:
|
||||
add_compiler(compiler_from_env())
|
||||
else:
|
||||
# for compiler in compilers.values():
|
||||
|
@ -501,7 +467,7 @@ short
|
|||
]
|
||||
lcomp3 = [
|
||||
# This one is actually too long to fit in a single line.
|
||||
element.split('\n', 1)[0]
|
||||
element.split("\n", 1)[0]
|
||||
for # yup
|
||||
element in collection.select_elements()
|
||||
if # right
|
||||
|
@ -518,7 +484,7 @@ short
|
|||
# let's return
|
||||
return Node(
|
||||
syms.simple_stmt,
|
||||
[Node(statement, result), Leaf(token.NEWLINE, '\n')], # FIXME: \r\n?
|
||||
[Node(statement, result), Leaf(token.NEWLINE, "\n")], # FIXME: \r\n?
|
||||
)
|
||||
|
||||
|
||||
|
|
|
@ -105,20 +105,7 @@ def g():
|
|||
```diff
|
||||
--- Black
|
||||
+++ Ruff
|
||||
@@ -3,9 +3,9 @@
|
||||
|
||||
# leading comment
|
||||
def f():
|
||||
- NO = ""
|
||||
- SPACE = " "
|
||||
- DOUBLESPACE = " "
|
||||
+ NO = ''
|
||||
+ SPACE = ' '
|
||||
+ DOUBLESPACE = ' '
|
||||
|
||||
t = leaf.type
|
||||
p = leaf.parent # trailing comment
|
||||
@@ -25,35 +25,41 @@
|
||||
@@ -25,23 +25,30 @@
|
||||
return NO
|
||||
|
||||
if prevp.type == token.EQUAL:
|
||||
|
@ -164,21 +151,14 @@ def g():
|
|||
return NO
|
||||
|
||||
|
||||
###############################################################################
|
||||
@@ -49,7 +56,6 @@
|
||||
# SECTION BECAUSE SECTIONS
|
||||
###############################################################################
|
||||
|
||||
-
|
||||
|
||||
def g():
|
||||
- NO = ""
|
||||
- SPACE = " "
|
||||
- DOUBLESPACE = " "
|
||||
+ NO = ''
|
||||
+ SPACE = ' '
|
||||
+ DOUBLESPACE = ' '
|
||||
|
||||
t = leaf.type
|
||||
p = leaf.parent
|
||||
NO = ""
|
||||
SPACE = " "
|
||||
@@ -67,7 +73,7 @@
|
||||
return DOUBLESPACE
|
||||
|
||||
|
@ -221,9 +201,9 @@ def g():
|
|||
|
||||
# leading comment
|
||||
def f():
|
||||
NO = ''
|
||||
SPACE = ' '
|
||||
DOUBLESPACE = ' '
|
||||
NO = ""
|
||||
SPACE = " "
|
||||
DOUBLESPACE = " "
|
||||
|
||||
t = leaf.type
|
||||
p = leaf.parent # trailing comment
|
||||
|
@ -275,9 +255,9 @@ def f():
|
|||
###############################################################################
|
||||
|
||||
def g():
|
||||
NO = ''
|
||||
SPACE = ' '
|
||||
DOUBLESPACE = ' '
|
||||
NO = ""
|
||||
SPACE = " "
|
||||
DOUBLESPACE = " "
|
||||
|
||||
t = leaf.type
|
||||
p = leaf.parent
|
||||
|
|
|
@ -268,22 +268,16 @@ last_call()
|
|||
--- Black
|
||||
+++ Ruff
|
||||
@@ -1,5 +1,6 @@
|
||||
-"some_string"
|
||||
-b"\\xa3"
|
||||
+...
|
||||
+'some_string'
|
||||
"some_string"
|
||||
-b"\\xa3"
|
||||
+b'\\xa3'
|
||||
Name
|
||||
None
|
||||
True
|
||||
@@ -35,10 +36,11 @@
|
||||
lambda arg: None
|
||||
lambda a=True: a
|
||||
lambda a, b, c=True: a
|
||||
-lambda a, b, c=True, *, d=(1 << v2), e="str": a
|
||||
-lambda a, b, c=True, *vararg, d=(v1 << 2), e="str", **kwargs: a + b
|
||||
+lambda a, b, c=True, *, d=(1 << v2), e='str': a
|
||||
+lambda a, b, c=True, *vararg, d=(v1 << 2), e='str', **kwargs: a + b
|
||||
@@ -38,7 +39,8 @@
|
||||
lambda a, b, c=True, *, d=(1 << v2), e="str": a
|
||||
lambda a, b, c=True, *vararg, d=(v1 << 2), e="str", **kwargs: a + b
|
||||
manylambdas = lambda x=lambda y=lambda z=1: z: y(): x()
|
||||
-foo = lambda port_id, ignore_missing: {
|
||||
+foo = lambda port_id,
|
||||
|
@ -291,38 +285,16 @@ last_call()
|
|||
"port1": port1_resource,
|
||||
"port2": port2_resource,
|
||||
}[port_id]
|
||||
@@ -52,11 +54,11 @@
|
||||
if (1 if super_long_test_name else 2)
|
||||
else (str or bytes or None)
|
||||
)
|
||||
-{"2.7": dead, "3.7": (long_live or die_hard)}
|
||||
-{"2.7": dead, "3.7": (long_live or die_hard), **{"3.6": verygood}}
|
||||
+{'2.7': dead, '3.7': (long_live or die_hard)}
|
||||
+{'2.7': dead, '3.7': (long_live or die_hard), **{'3.6': verygood}}
|
||||
@@ -56,7 +58,7 @@
|
||||
{"2.7": dead, "3.7": (long_live or die_hard), **{"3.6": verygood}}
|
||||
{**a, **b, **c}
|
||||
-{"2.7", "3.6", "3.7", "3.8", "3.9", ("4.0" if gilectomy else "3.10")}
|
||||
{"2.7", "3.6", "3.7", "3.8", "3.9", ("4.0" if gilectomy else "3.10")}
|
||||
-({"a": "b"}, (True or False), (+value), "string", b"bytes") or None
|
||||
+{'2.7', '3.6', '3.7', '3.8', '3.9', ('4.0' if gilectomy else '3.10')}
|
||||
+({'a': 'b'}, (True or False), (+value), 'string', b'bytes') or None
|
||||
+({"a": "b"}, (True or False), (+value), "string", b'bytes') or None
|
||||
()
|
||||
(1,)
|
||||
(1, 2)
|
||||
@@ -88,32 +90,33 @@
|
||||
]
|
||||
{i for i in (1, 2, 3)}
|
||||
{(i**2) for i in (1, 2, 3)}
|
||||
-{(i**2) for i, _ in ((1, "a"), (2, "b"), (3, "c"))}
|
||||
+{(i**2) for i, _ in ((1, 'a'), (2, 'b'), (3, 'c'))}
|
||||
{((i**2) + j) for i in (1, 2, 3) for j in (1, 2, 3)}
|
||||
[i for i in (1, 2, 3)]
|
||||
[(i**2) for i in (1, 2, 3)]
|
||||
-[(i**2) for i, _ in ((1, "a"), (2, "b"), (3, "c"))]
|
||||
+[(i**2) for i, _ in ((1, 'a'), (2, 'b'), (3, 'c'))]
|
||||
[((i**2) + j) for i in (1, 2, 3) for j in (1, 2, 3)]
|
||||
{i: 0 for i in (1, 2, 3)}
|
||||
-{i: j for i, j in ((1, "a"), (2, "b"), (3, "c"))}
|
||||
+{i: j for i, j in ((1, 'a'), (2, 'b'), (3, 'c'))}
|
||||
{a: b * 2 for a, b in dictionary.items()}
|
||||
@@ -100,7 +102,8 @@
|
||||
{a: b * -2 for a, b in dictionary.items()}
|
||||
{
|
||||
k: v
|
||||
|
@ -332,23 +304,6 @@ last_call()
|
|||
}
|
||||
Python3 > Python2 > COBOL
|
||||
Life is Life
|
||||
call()
|
||||
call(arg)
|
||||
-call(kwarg="hey")
|
||||
-call(arg, kwarg="hey")
|
||||
-call(arg, another, kwarg="hey", **kwargs)
|
||||
+call(kwarg='hey')
|
||||
+call(arg, kwarg='hey')
|
||||
+call(arg, another, kwarg='hey', **kwargs)
|
||||
call(
|
||||
this_is_a_very_long_variable_which_will_force_a_delimiter_split,
|
||||
arg,
|
||||
another,
|
||||
- kwarg="hey",
|
||||
+ kwarg='hey',
|
||||
**kwargs,
|
||||
) # note: no trailing comma pre-3.6
|
||||
call(*gidgets[:2])
|
||||
@@ -122,8 +125,8 @@
|
||||
call(b, **self.screen_kwargs)
|
||||
lukasz.langa.pl
|
||||
|
@ -367,19 +322,19 @@ last_call()
|
|||
-xxxx_xxxxx_xxxx_xxx: Callable[..., List[SomeClass]] = classmethod( # type: ignore
|
||||
- sync(async_xxxx_xxx_xxxx_xxxxx_xxxx_xxx.__func__)
|
||||
+xxxx_xxxxx_xxxx_xxx: Callable[..., List[SomeClass]] = (
|
||||
+ classmethod(sync(async_xxxx_xxx_xxxx_xxxxx_xxxx_xxx.__func__)) # type: ignore
|
||||
+)
|
||||
+xxxx_xxx_xxxx_xxxxx_xxxx_xxx: Callable[..., List[SomeClass]] = (
|
||||
+ classmethod(sync(async_xxxx_xxx_xxxx_xxxxx_xxxx_xxx.__func__)) # type: ignore
|
||||
)
|
||||
-xxxx_xxx_xxxx_xxxxx_xxxx_xxx: Callable[..., List[SomeClass]] = classmethod( # type: ignore
|
||||
- sync(async_xxxx_xxx_xxxx_xxxxx_xxxx_xxx.__func__)
|
||||
+xxxx_xxx_xxxx_xxxxx_xxxx_xxx: Callable[..., List[SomeClass]] = (
|
||||
+ classmethod(sync(async_xxxx_xxx_xxxx_xxxxx_xxxx_xxx.__func__)) # type: ignore
|
||||
+ classmethod(sync(async_xxxx_xxx_xxxx_xxxxx_xxxx_xxx.__func__))
|
||||
)
|
||||
-xxxx_xxx_xxxx_xxxxx_xxxx_xxx: Callable[..., List[SomeClass]] = classmethod(
|
||||
- sync(async_xxxx_xxx_xxxx_xxxxx_xxxx_xxx.__func__)
|
||||
-) # type: ignore
|
||||
+xxxx_xxx_xxxx_xxxxx_xxxx_xxx: Callable[..., List[SomeClass]] = (
|
||||
+ classmethod(sync(async_xxxx_xxx_xxxx_xxxxx_xxxx_xxx.__func__))
|
||||
+)
|
||||
slice[0]
|
||||
slice[0:1]
|
||||
slice[0:1:2]
|
||||
|
@ -405,46 +360,25 @@ last_call()
|
|||
numpy[:, (0, 1, 2, 5)]
|
||||
numpy[0, [0]]
|
||||
numpy[:, [i]]
|
||||
@@ -172,17 +175,17 @@
|
||||
@@ -172,7 +175,7 @@
|
||||
numpy[-(c + 1) :, d]
|
||||
numpy[:, l[-2]]
|
||||
numpy[:, ::-1]
|
||||
-numpy[np.newaxis, :]
|
||||
+numpy[np.newaxis, ::]
|
||||
(str or None) if (sys.version_info[0] > (3,)) else (str or bytes or None)
|
||||
-{"2.7": dead, "3.7": long_live or die_hard}
|
||||
-{"2.7", "3.6", "3.7", "3.8", "3.9", "4.0" if gilectomy else "3.10"}
|
||||
+{'2.7': dead, '3.7': long_live or die_hard}
|
||||
+{'2.7', '3.6', '3.7', '3.8', '3.9', '4.0' if gilectomy else '3.10'}
|
||||
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10 or A, 11 or B, 12 or C]
|
||||
(SomeName)
|
||||
SomeName
|
||||
(Good, Bad, Ugly)
|
||||
(i for i in (1, 2, 3))
|
||||
((i**2) for i in (1, 2, 3))
|
||||
-((i**2) for i, _ in ((1, "a"), (2, "b"), (3, "c")))
|
||||
+((i**2) for i, _ in ((1, 'a'), (2, 'b'), (3, 'c')))
|
||||
(((i**2) + j) for i in (1, 2, 3) for j in (1, 2, 3))
|
||||
(*starred,)
|
||||
{
|
||||
{"2.7": dead, "3.7": long_live or die_hard}
|
||||
{"2.7", "3.6", "3.7", "3.8", "3.9", "4.0" if gilectomy else "3.10"}
|
||||
@@ -201,30 +204,26 @@
|
||||
e = (1,).count(1)
|
||||
f = 1, *range(10)
|
||||
g = 1, *"ten"
|
||||
-what_is_up_with_those_new_coord_names = (coord_names + set(vars_to_create)) + set(
|
||||
- vars_to_remove
|
||||
+what_is_up_with_those_new_coord_names = (
|
||||
+ (coord_names
|
||||
+ + set(vars_to_create))
|
||||
+ + set(vars_to_remove)
|
||||
)
|
||||
-)
|
||||
-what_is_up_with_those_new_coord_names = (coord_names | set(vars_to_create)) - set(
|
||||
- vars_to_remove
|
||||
+what_is_up_with_those_new_coord_names = (
|
||||
+ (coord_names
|
||||
+ | set(vars_to_create))
|
||||
+ - set(vars_to_remove)
|
||||
)
|
||||
-)
|
||||
-result = (
|
||||
- session.query(models.Customer.id)
|
||||
- .filter(
|
||||
|
@ -452,7 +386,11 @@ last_call()
|
|||
- )
|
||||
- .order_by(models.Customer.id.asc())
|
||||
- .all()
|
||||
-)
|
||||
+what_is_up_with_those_new_coord_names = (
|
||||
+ (coord_names
|
||||
+ + set(vars_to_create))
|
||||
+ + set(vars_to_remove)
|
||||
)
|
||||
-result = (
|
||||
- session.query(models.Customer.id)
|
||||
- .filter(
|
||||
|
@ -462,7 +400,11 @@ last_call()
|
|||
- models.Customer.id.asc(),
|
||||
- )
|
||||
- .all()
|
||||
-)
|
||||
+what_is_up_with_those_new_coord_names = (
|
||||
+ (coord_names
|
||||
+ | set(vars_to_create))
|
||||
+ - set(vars_to_remove)
|
||||
)
|
||||
+result = session.query(models.Customer.id).filter(
|
||||
+ models.Customer.account_id == account_id,
|
||||
+ models.Customer.email == email_address,
|
||||
|
@ -489,15 +431,6 @@ last_call()
|
|||
assert parens is TooMany
|
||||
for (x,) in (1,), (2,), (3,):
|
||||
...
|
||||
@@ -272,7 +271,7 @@
|
||||
addr_proto,
|
||||
addr_canonname,
|
||||
addr_sockaddr,
|
||||
-) in socket.getaddrinfo("google.com", "http"):
|
||||
+) in socket.getaddrinfo('google.com', 'http'):
|
||||
pass
|
||||
a = (
|
||||
aaaa.bbbb.cccc.dddd.eeee.ffff.gggg.hhhh.iiii.jjjj.kkkk.llll.mmmm.nnnn.oooo.pppp
|
||||
@@ -327,13 +326,18 @@
|
||||
):
|
||||
return True
|
||||
|
@ -536,7 +469,7 @@ last_call()
|
|||
|
||||
```py
|
||||
...
|
||||
'some_string'
|
||||
"some_string"
|
||||
b'\\xa3'
|
||||
Name
|
||||
None
|
||||
|
@ -573,8 +506,8 @@ flags & ~select.EPOLLIN and waiters.write_task is not None
|
|||
lambda arg: None
|
||||
lambda a=True: a
|
||||
lambda a, b, c=True: a
|
||||
lambda a, b, c=True, *, d=(1 << v2), e='str': a
|
||||
lambda a, b, c=True, *vararg, d=(v1 << 2), e='str', **kwargs: a + b
|
||||
lambda a, b, c=True, *, d=(1 << v2), e="str": a
|
||||
lambda a, b, c=True, *vararg, d=(v1 << 2), e="str", **kwargs: a + b
|
||||
manylambdas = lambda x=lambda y=lambda z=1: z: y(): x()
|
||||
foo = lambda port_id,
|
||||
ignore_missing,: {
|
||||
|
@ -591,11 +524,11 @@ str or None if (1 if True else 2) else str or bytes or None
|
|||
if (1 if super_long_test_name else 2)
|
||||
else (str or bytes or None)
|
||||
)
|
||||
{'2.7': dead, '3.7': (long_live or die_hard)}
|
||||
{'2.7': dead, '3.7': (long_live or die_hard), **{'3.6': verygood}}
|
||||
{"2.7": dead, "3.7": (long_live or die_hard)}
|
||||
{"2.7": dead, "3.7": (long_live or die_hard), **{"3.6": verygood}}
|
||||
{**a, **b, **c}
|
||||
{'2.7', '3.6', '3.7', '3.8', '3.9', ('4.0' if gilectomy else '3.10')}
|
||||
({'a': 'b'}, (True or False), (+value), 'string', b'bytes') or None
|
||||
{"2.7", "3.6", "3.7", "3.8", "3.9", ("4.0" if gilectomy else "3.10")}
|
||||
({"a": "b"}, (True or False), (+value), "string", b'bytes') or None
|
||||
()
|
||||
(1,)
|
||||
(1, 2)
|
||||
|
@ -627,14 +560,14 @@ str or None if (1 if True else 2) else str or bytes or None
|
|||
]
|
||||
{i for i in (1, 2, 3)}
|
||||
{(i**2) for i in (1, 2, 3)}
|
||||
{(i**2) for i, _ in ((1, 'a'), (2, 'b'), (3, 'c'))}
|
||||
{(i**2) for i, _ in ((1, "a"), (2, "b"), (3, "c"))}
|
||||
{((i**2) + j) for i in (1, 2, 3) for j in (1, 2, 3)}
|
||||
[i for i in (1, 2, 3)]
|
||||
[(i**2) for i in (1, 2, 3)]
|
||||
[(i**2) for i, _ in ((1, 'a'), (2, 'b'), (3, 'c'))]
|
||||
[(i**2) for i, _ in ((1, "a"), (2, "b"), (3, "c"))]
|
||||
[((i**2) + j) for i in (1, 2, 3) for j in (1, 2, 3)]
|
||||
{i: 0 for i in (1, 2, 3)}
|
||||
{i: j for i, j in ((1, 'a'), (2, 'b'), (3, 'c'))}
|
||||
{i: j for i, j in ((1, "a"), (2, "b"), (3, "c"))}
|
||||
{a: b * 2 for a, b in dictionary.items()}
|
||||
{a: b * -2 for a, b in dictionary.items()}
|
||||
{
|
||||
|
@ -646,14 +579,14 @@ Python3 > Python2 > COBOL
|
|||
Life is Life
|
||||
call()
|
||||
call(arg)
|
||||
call(kwarg='hey')
|
||||
call(arg, kwarg='hey')
|
||||
call(arg, another, kwarg='hey', **kwargs)
|
||||
call(kwarg="hey")
|
||||
call(arg, kwarg="hey")
|
||||
call(arg, another, kwarg="hey", **kwargs)
|
||||
call(
|
||||
this_is_a_very_long_variable_which_will_force_a_delimiter_split,
|
||||
arg,
|
||||
another,
|
||||
kwarg='hey',
|
||||
kwarg="hey",
|
||||
**kwargs,
|
||||
) # note: no trailing comma pre-3.6
|
||||
call(*gidgets[:2])
|
||||
|
@ -714,15 +647,15 @@ numpy[:, l[-2]]
|
|||
numpy[:, ::-1]
|
||||
numpy[np.newaxis, ::]
|
||||
(str or None) if (sys.version_info[0] > (3,)) else (str or bytes or None)
|
||||
{'2.7': dead, '3.7': long_live or die_hard}
|
||||
{'2.7', '3.6', '3.7', '3.8', '3.9', '4.0' if gilectomy else '3.10'}
|
||||
{"2.7": dead, "3.7": long_live or die_hard}
|
||||
{"2.7", "3.6", "3.7", "3.8", "3.9", "4.0" if gilectomy else "3.10"}
|
||||
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10 or A, 11 or B, 12 or C]
|
||||
(SomeName)
|
||||
SomeName
|
||||
(Good, Bad, Ugly)
|
||||
(i for i in (1, 2, 3))
|
||||
((i**2) for i in (1, 2, 3))
|
||||
((i**2) for i, _ in ((1, 'a'), (2, 'b'), (3, 'c')))
|
||||
((i**2) for i, _ in ((1, "a"), (2, "b"), (3, "c")))
|
||||
(((i**2) + j) for i in (1, 2, 3) for j in (1, 2, 3))
|
||||
(*starred,)
|
||||
{
|
||||
|
@ -808,7 +741,7 @@ for (
|
|||
addr_proto,
|
||||
addr_canonname,
|
||||
addr_sockaddr,
|
||||
) in socket.getaddrinfo('google.com', 'http'):
|
||||
) in socket.getaddrinfo("google.com", "http"):
|
||||
pass
|
||||
a = (
|
||||
aaaa.bbbb.cccc.dddd.eeee.ffff.gggg.hhhh.iiii.jjjj.kkkk.llll.mmmm.nnnn.oooo.pppp
|
||||
|
|
|
@ -67,11 +67,11 @@ def test_calculate_fades():
|
|||
-
|
||||
- # Test don't manage the volume
|
||||
+@pytest.mark.parametrize(
|
||||
+ 'test',
|
||||
+ "test",
|
||||
[
|
||||
- ('stuff', 'in')
|
||||
+ # Test don't manage the volume
|
||||
+ [('stuff', 'in')],
|
||||
+ [("stuff", "in")],
|
||||
],
|
||||
-])
|
||||
+)
|
||||
|
@ -123,10 +123,10 @@ TmEx = 2
|
|||
# Position, Volume, State, TmSt/TmEx/None, [call, [arg1...]]
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
'test',
|
||||
"test",
|
||||
[
|
||||
# Test don't manage the volume
|
||||
[('stuff', 'in')],
|
||||
[("stuff", "in")],
|
||||
],
|
||||
)
|
||||
def test_fader(test):
|
||||
|
|
|
@ -97,17 +97,20 @@ elif unformatted:
|
|||
```diff
|
||||
--- Black
|
||||
+++ Ruff
|
||||
@@ -5,8 +5,7 @@
|
||||
@@ -3,10 +3,8 @@
|
||||
entry_points={
|
||||
# fmt: off
|
||||
"console_scripts": [
|
||||
"foo-bar"
|
||||
"=foo.bar.:main",
|
||||
- "foo-bar"
|
||||
- "=foo.bar.:main",
|
||||
- # fmt: on
|
||||
- ] # Includes an formatted indentation.
|
||||
+ "foo-bar" "=foo.bar.:main",
|
||||
+ ],
|
||||
},
|
||||
)
|
||||
|
||||
@@ -18,8 +17,8 @@
|
||||
@@ -18,8 +16,8 @@
|
||||
"ls",
|
||||
"-la",
|
||||
]
|
||||
|
@ -118,7 +121,7 @@ elif unformatted:
|
|||
check=True,
|
||||
)
|
||||
|
||||
@@ -27,9 +26,8 @@
|
||||
@@ -27,9 +25,8 @@
|
||||
# Regression test for https://github.com/psf/black/issues/3026.
|
||||
def test_func():
|
||||
# yapf: disable
|
||||
|
@ -129,7 +132,7 @@ elif unformatted:
|
|||
elif b:
|
||||
return True
|
||||
|
||||
@@ -39,10 +37,10 @@
|
||||
@@ -39,10 +36,10 @@
|
||||
# Regression test for https://github.com/psf/black/issues/2567.
|
||||
if True:
|
||||
# fmt: off
|
||||
|
@ -144,7 +147,7 @@ elif unformatted:
|
|||
else:
|
||||
print("This will be formatted")
|
||||
|
||||
@@ -52,14 +50,11 @@
|
||||
@@ -52,14 +49,11 @@
|
||||
async def call(param):
|
||||
if param:
|
||||
# fmt: off
|
||||
|
@ -162,7 +165,7 @@ elif unformatted:
|
|||
|
||||
print("This will be formatted")
|
||||
|
||||
@@ -68,20 +63,21 @@
|
||||
@@ -68,20 +62,21 @@
|
||||
class Named(t.Protocol):
|
||||
# fmt: off
|
||||
@property
|
||||
|
@ -198,8 +201,7 @@ setup(
|
|||
entry_points={
|
||||
# fmt: off
|
||||
"console_scripts": [
|
||||
"foo-bar"
|
||||
"=foo.bar.:main",
|
||||
"foo-bar" "=foo.bar.:main",
|
||||
],
|
||||
},
|
||||
)
|
||||
|
|
|
@ -117,32 +117,7 @@ def __await__(): return (yield)
|
|||
|
||||
|
||||
def func_no_args():
|
||||
@@ -27,7 +27,7 @@
|
||||
async def coroutine(arg, exec=False):
|
||||
"Single-line docstring. Multiline is harder to reformat."
|
||||
async with some_connection() as conn:
|
||||
- await conn.do_what_i_mean("SELECT bobby, tables FROM xkcd", timeout=2)
|
||||
+ await conn.do_what_i_mean('SELECT bobby, tables FROM xkcd', timeout=2)
|
||||
await asyncio.sleep(1)
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
return text[number:-1]
|
||||
|
||||
|
||||
-def spaces(a=1, b=(), c=[], d={}, e=True, f=-1, g=1 if False else 2, h="", i=r""):
|
||||
+def spaces(a=1, b=(), c=[], d={}, e=True, f=-1, g=1 if False else 2, h="", i=r''):
|
||||
offset = attr.ib(default=attr.Factory(lambda: _r.uniform(10000, 200000)))
|
||||
assert task._cancel_stack[: len(old_stack)] == old_stack
|
||||
|
||||
@@ -58,25 +58,20 @@
|
||||
f: int = -1,
|
||||
g: int = 1 if False else 2,
|
||||
h: str = "",
|
||||
- i: str = r"",
|
||||
+ i: str = r'',
|
||||
):
|
||||
...
|
||||
@@ -64,19 +64,14 @@
|
||||
|
||||
|
||||
def spaces2(result=_core.Value(None)):
|
||||
|
@ -218,7 +193,7 @@ def func_no_args():
|
|||
async def coroutine(arg, exec=False):
|
||||
"Single-line docstring. Multiline is harder to reformat."
|
||||
async with some_connection() as conn:
|
||||
await conn.do_what_i_mean('SELECT bobby, tables FROM xkcd', timeout=2)
|
||||
await conn.do_what_i_mean("SELECT bobby, tables FROM xkcd", timeout=2)
|
||||
await asyncio.sleep(1)
|
||||
|
||||
|
||||
|
@ -235,7 +210,7 @@ def function_signature_stress_test(
|
|||
return text[number:-1]
|
||||
|
||||
|
||||
def spaces(a=1, b=(), c=[], d={}, e=True, f=-1, g=1 if False else 2, h="", i=r''):
|
||||
def spaces(a=1, b=(), c=[], d={}, e=True, f=-1, g=1 if False else 2, h="", i=r""):
|
||||
offset = attr.ib(default=attr.Factory(lambda: _r.uniform(10000, 200000)))
|
||||
assert task._cancel_stack[: len(old_stack)] == old_stack
|
||||
|
||||
|
@ -249,7 +224,7 @@ def spaces_types(
|
|||
f: int = -1,
|
||||
g: int = 1 if False else 2,
|
||||
h: str = "",
|
||||
i: str = r'',
|
||||
i: str = r"",
|
||||
):
|
||||
...
|
||||
|
||||
|
|
|
@ -74,35 +74,6 @@ some_module.some_function(
|
|||
```diff
|
||||
--- Black
|
||||
+++ Ruff
|
||||
@@ -2,7 +2,7 @@
|
||||
a,
|
||||
):
|
||||
d = {
|
||||
- "key": "value",
|
||||
+ 'key': 'value',
|
||||
}
|
||||
tup = (1,)
|
||||
|
||||
@@ -12,8 +12,8 @@
|
||||
b,
|
||||
):
|
||||
d = {
|
||||
- "key": "value",
|
||||
- "key2": "value2",
|
||||
+ 'key': 'value',
|
||||
+ 'key2': 'value2',
|
||||
}
|
||||
tup = (
|
||||
1,
|
||||
@@ -26,7 +26,7 @@
|
||||
):
|
||||
call(
|
||||
arg={
|
||||
- "explode": "this",
|
||||
+ 'explode': 'this',
|
||||
}
|
||||
)
|
||||
call2(
|
||||
@@ -52,53 +52,52 @@
|
||||
pass
|
||||
|
||||
|
@ -184,7 +155,7 @@ def f(
|
|||
a,
|
||||
):
|
||||
d = {
|
||||
'key': 'value',
|
||||
"key": "value",
|
||||
}
|
||||
tup = (1,)
|
||||
|
||||
|
@ -194,8 +165,8 @@ def f2(
|
|||
b,
|
||||
):
|
||||
d = {
|
||||
'key': 'value',
|
||||
'key2': 'value2',
|
||||
"key": "value",
|
||||
"key2": "value2",
|
||||
}
|
||||
tup = (
|
||||
1,
|
||||
|
@ -208,7 +179,7 @@ def f(
|
|||
):
|
||||
call(
|
||||
arg={
|
||||
'explode': 'this',
|
||||
"explode": "this",
|
||||
}
|
||||
)
|
||||
call2(
|
||||
|
|
|
@ -39,10 +39,9 @@ def docstring_multiline():
|
|||
name = "Łukasz"
|
||||
-(f"hello {name}", f"hello {name}")
|
||||
-(b"", b"")
|
||||
-("", "")
|
||||
+(f"hello {name}", F"hello {name}")
|
||||
+(b"", B"")
|
||||
+(u"", U"")
|
||||
("", "")
|
||||
(r"", R"")
|
||||
|
||||
-(rf"", rf"", Rf"", Rf"", rf"", rf"", Rf"", Rf"")
|
||||
|
@ -62,7 +61,7 @@ def docstring_multiline():
|
|||
name = "Łukasz"
|
||||
(f"hello {name}", F"hello {name}")
|
||||
(b"", B"")
|
||||
(u"", U"")
|
||||
("", "")
|
||||
(r"", R"")
|
||||
|
||||
(rf"", fr"", Rf"", fR"", rF"", Fr"", RF"", FR"")
|
||||
|
|
|
@ -38,7 +38,7 @@ class A:
|
|||
```diff
|
||||
--- Black
|
||||
+++ Ruff
|
||||
@@ -1,15 +1,14 @@
|
||||
@@ -1,7 +1,6 @@
|
||||
-if e1234123412341234.winerror not in (
|
||||
- _winapi.ERROR_SEM_TIMEOUT,
|
||||
- _winapi.ERROR_PIPE_BUSY,
|
||||
|
@ -49,23 +49,13 @@ class A:
|
|||
pass
|
||||
|
||||
if x:
|
||||
if y:
|
||||
new_id = (
|
||||
max(
|
||||
- Vegetable.objects.order_by("-id")[0].id,
|
||||
- Mineral.objects.order_by("-id")[0].id,
|
||||
+ Vegetable.objects.order_by('-id')[0].id,
|
||||
+ Mineral.objects.order_by('-id')[0].id,
|
||||
)
|
||||
+ 1
|
||||
)
|
||||
@@ -21,14 +20,20 @@
|
||||
"Your password must contain at least %(min_length)d character.",
|
||||
"Your password must contain at least %(min_length)d characters.",
|
||||
self.min_length,
|
||||
- ) % {"min_length": self.min_length}
|
||||
+ )
|
||||
+ % {'min_length': self.min_length}
|
||||
+ % {"min_length": self.min_length}
|
||||
|
||||
|
||||
class A:
|
||||
|
@ -100,8 +90,8 @@ if x:
|
|||
if y:
|
||||
new_id = (
|
||||
max(
|
||||
Vegetable.objects.order_by('-id')[0].id,
|
||||
Mineral.objects.order_by('-id')[0].id,
|
||||
Vegetable.objects.order_by("-id")[0].id,
|
||||
Mineral.objects.order_by("-id")[0].id,
|
||||
)
|
||||
+ 1
|
||||
)
|
||||
|
@ -114,7 +104,7 @@ class X:
|
|||
"Your password must contain at least %(min_length)d characters.",
|
||||
self.min_length,
|
||||
)
|
||||
% {'min_length': self.min_length}
|
||||
% {"min_length": self.min_length}
|
||||
|
||||
|
||||
class A:
|
||||
|
|
|
@ -23,7 +23,7 @@ if (e123456.get_tk_patchlevel() >= (8, 6, 0, 'final') or
|
|||
- 8,
|
||||
-) <= get_tk_patchlevel() < (8, 6):
|
||||
+if (
|
||||
+ e123456.get_tk_patchlevel() >= (8, 6, 0, 'final')
|
||||
+ e123456.get_tk_patchlevel() >= (8, 6, 0, "final")
|
||||
+ or (8, 5, 8) <= get_tk_patchlevel() < (8, 6)
|
||||
+):
|
||||
pass
|
||||
|
@ -33,7 +33,7 @@ if (e123456.get_tk_patchlevel() >= (8, 6, 0, 'final') or
|
|||
|
||||
```py
|
||||
if (
|
||||
e123456.get_tk_patchlevel() >= (8, 6, 0, 'final')
|
||||
e123456.get_tk_patchlevel() >= (8, 6, 0, "final")
|
||||
or (8, 5, 8) <= get_tk_patchlevel() < (8, 6)
|
||||
):
|
||||
pass
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue