Update Black tests (#5438)

This commit is contained in:
Micha Reiser 2023-06-30 08:32:50 +02:00 committed by GitHub
parent f7969cf23c
commit ae25638b0b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
166 changed files with 11066 additions and 237 deletions

View file

@ -0,0 +1,67 @@
long_kwargs_single_line = my_function(
foo="test, this is a sample value",
bar=some_long_value_name_foo_bar_baz if some_boolean_variable else some_fallback_value_foo_bar_baz,
baz="hello, this is a another value",
)
multiline_kwargs_indented = my_function(
foo="test, this is a sample value",
bar=some_long_value_name_foo_bar_baz
if some_boolean_variable
else some_fallback_value_foo_bar_baz,
baz="hello, this is a another value",
)
imploding_kwargs = my_function(
foo="test, this is a sample value",
bar=a
if foo
else b,
baz="hello, this is a another value",
)
imploding_line = (
1
if 1 + 1 == 2
else 0
)
exploding_line = "hello this is a slightly long string" if some_long_value_name_foo_bar_baz else "this one is a little shorter"
positional_argument_test(some_long_value_name_foo_bar_baz if some_boolean_variable else some_fallback_value_foo_bar_baz)
def weird_default_argument(x=some_long_value_name_foo_bar_baz
if SOME_CONSTANT
else some_fallback_value_foo_bar_baz):
pass
nested = "hello this is a slightly long string" if (some_long_value_name_foo_bar_baz if
nesting_test_expressions else some_fallback_value_foo_bar_baz) \
else "this one is a little shorter"
generator_expression = (
some_long_value_name_foo_bar_baz if some_boolean_variable else some_fallback_value_foo_bar_baz for some_boolean_variable in some_iterable
)
def limit_offset_sql(self, low_mark, high_mark):
"""Return LIMIT/OFFSET SQL clause."""
limit, offset = self._get_limit_offset_params(low_mark, high_mark)
return " ".join(
sql
for sql in (
"LIMIT %d" % limit if limit else None,
("OFFSET %d" % offset) if offset else None,
)
if sql
)
def something():
clone._iterable_class = (
NamedValuesListIterable
if named
else FlatValuesListIterable
if flat
else ValuesListIterable
)

View file

@ -0,0 +1,90 @@
long_kwargs_single_line = my_function(
foo="test, this is a sample value",
bar=(
some_long_value_name_foo_bar_baz
if some_boolean_variable
else some_fallback_value_foo_bar_baz
),
baz="hello, this is a another value",
)
multiline_kwargs_indented = my_function(
foo="test, this is a sample value",
bar=(
some_long_value_name_foo_bar_baz
if some_boolean_variable
else some_fallback_value_foo_bar_baz
),
baz="hello, this is a another value",
)
imploding_kwargs = my_function(
foo="test, this is a sample value",
bar=a if foo else b,
baz="hello, this is a another value",
)
imploding_line = 1 if 1 + 1 == 2 else 0
exploding_line = (
"hello this is a slightly long string"
if some_long_value_name_foo_bar_baz
else "this one is a little shorter"
)
positional_argument_test(
some_long_value_name_foo_bar_baz
if some_boolean_variable
else some_fallback_value_foo_bar_baz
)
def weird_default_argument(
x=(
some_long_value_name_foo_bar_baz
if SOME_CONSTANT
else some_fallback_value_foo_bar_baz
),
):
pass
nested = (
"hello this is a slightly long string"
if (
some_long_value_name_foo_bar_baz
if nesting_test_expressions
else some_fallback_value_foo_bar_baz
)
else "this one is a little shorter"
)
generator_expression = (
(
some_long_value_name_foo_bar_baz
if some_boolean_variable
else some_fallback_value_foo_bar_baz
)
for some_boolean_variable in some_iterable
)
def limit_offset_sql(self, low_mark, high_mark):
"""Return LIMIT/OFFSET SQL clause."""
limit, offset = self._get_limit_offset_params(low_mark, high_mark)
return " ".join(
sql
for sql in (
"LIMIT %d" % limit if limit else None,
("OFFSET %d" % offset) if offset else None,
)
if sql
)
def something():
clone._iterable_class = (
NamedValuesListIterable
if named
else FlatValuesListIterable if flat else ValuesListIterable
)

View file

@ -0,0 +1,6 @@
def abc ():
return ["hello", "world",
"!"]
print( "Incorrect formatting"
)

View file

@ -0,0 +1,6 @@
def abc ():
return ["hello", "world",
"!"]
print( "Incorrect formatting"
)

View file

@ -0,0 +1,32 @@
@dataclass
class DebugVisitor(Visitor[T]):
tree_depth: int = 0
def visit_default(self, node: LN) -> Iterator[T]:
indent = ' ' * (2 * self.tree_depth)
if isinstance(node, Node):
_type = type_repr(node.type)
out(f'{indent}{_type}', fg='yellow')
self.tree_depth += 1
for child in node.children:
yield from self.visit(child)
self.tree_depth -= 1
out(f'{indent}/{_type}', fg='yellow', bold=False)
else:
_type = token.tok_name.get(node.type, str(node.type))
out(f'{indent}{_type}', fg='blue', nl=False)
if node.prefix:
# We don't have to handle prefixes for `Node` objects since
# that delegates to the first child anyway.
out(f' {node.prefix!r}', fg='green', bold=False, nl=False)
out(f' {node.value!r}', fg='blue', bold=False)
@classmethod
def show(cls, code: str) -> None:
"""Pretty-prints a given string of `code`.
Convenience method for debugging.
"""
v: DebugVisitor[None] = DebugVisitor()
list(v.visit(lib2to3_parse(code)))

View file

@ -0,0 +1,32 @@
@dataclass
class DebugVisitor(Visitor[T]):
tree_depth: int = 0
def visit_default(self, node: LN) -> Iterator[T]:
indent = ' ' * (2 * self.tree_depth)
if isinstance(node, Node):
_type = type_repr(node.type)
out(f'{indent}{_type}', fg='yellow')
self.tree_depth += 1
for child in node.children:
yield from self.visit(child)
self.tree_depth -= 1
out(f'{indent}/{_type}', fg='yellow', bold=False)
else:
_type = token.tok_name.get(node.type, str(node.type))
out(f'{indent}{_type}', fg='blue', nl=False)
if node.prefix:
# We don't have to handle prefixes for `Node` objects since
# that delegates to the first child anyway.
out(f' {node.prefix!r}', fg='green', bold=False, nl=False)
out(f' {node.value!r}', fg='blue', bold=False)
@classmethod
def show(cls, code: str) -> None:
"""Pretty-prints a given string of `code`.
Convenience method for debugging.
"""
v: DebugVisitor[None] = DebugVisitor()
list(v.visit(lib2to3_parse(code)))

View file

@ -0,0 +1,150 @@
# This file doesn't use the standard decomposition.
# Decorator syntax test cases are separated by double # comments.
# Those before the 'output' comment are valid under the old syntax.
# Those after the 'ouput' comment require PEP614 relaxed syntax.
# Do not remove the double # separator before the first test case, it allows
# the comment before the test case to be ignored.
##
@decorator
def f():
...
##
@decorator()
def f():
...
##
@decorator(arg)
def f():
...
##
@decorator(kwarg=0)
def f():
...
##
@decorator(*args)
def f():
...
##
@decorator(**kwargs)
def f():
...
##
@decorator(*args, **kwargs)
def f():
...
##
@decorator(*args, **kwargs,)
def f():
...
##
@dotted.decorator
def f():
...
##
@dotted.decorator(arg)
def f():
...
##
@dotted.decorator(kwarg=0)
def f():
...
##
@dotted.decorator(*args)
def f():
...
##
@dotted.decorator(**kwargs)
def f():
...
##
@dotted.decorator(*args, **kwargs)
def f():
...
##
@dotted.decorator(*args, **kwargs,)
def f():
...
##
@double.dotted.decorator
def f():
...
##
@double.dotted.decorator(arg)
def f():
...
##
@double.dotted.decorator(kwarg=0)
def f():
...
##
@double.dotted.decorator(*args)
def f():
...
##
@double.dotted.decorator(**kwargs)
def f():
...
##
@double.dotted.decorator(*args, **kwargs)
def f():
...
##
@double.dotted.decorator(*args, **kwargs,)
def f():
...
##
@_(sequence["decorator"])
def f():
...
##
@eval("sequence['decorator']")
def f():
...

View file

@ -0,0 +1,29 @@
##
@decorator()()
def f():
...
##
@(decorator)
def f():
...
##
@sequence["decorator"]
def f():
...
##
@decorator[List[str]]
def f():
...
##
@var := decorator
def f():
...

View file

@ -0,0 +1,123 @@
class ALonelyClass:
'''
A multiline class docstring.
'''
def AnEquallyLonelyMethod(self):
'''
A multiline method docstring'''
pass
def one_function():
'''This is a docstring with a single line of text.'''
pass
def shockingly_the_quotes_are_normalized():
'''This is a multiline docstring.
This is a multiline docstring.
This is a multiline docstring.
'''
pass
def foo():
"""This is a docstring with
some lines of text here
"""
return
def baz():
'''"This" is a string with some
embedded "quotes"'''
return
def poit():
"""
Lorem ipsum dolor sit amet.
Consectetur adipiscing elit:
- sed do eiusmod tempor incididunt ut labore
- dolore magna aliqua
- enim ad minim veniam
- quis nostrud exercitation ullamco laboris nisi
- aliquip ex ea commodo consequat
"""
pass
def under_indent():
"""
These lines are indented in a way that does not
make sense.
"""
pass
def over_indent():
"""
This has a shallow indent
- But some lines are deeper
- And the closing quote is too deep
"""
pass
def single_line():
"""But with a newline after it!
"""
pass
def this():
r"""
'hey ho'
"""
def that():
""" "hey yah" """
def and_that():
"""
"hey yah" """
def and_this():
'''
"hey yah"'''
def believe_it_or_not_this_is_in_the_py_stdlib(): '''
"hey yah"'''
def shockingly_the_quotes_are_normalized_v2():
'''
Docstring Docstring Docstring
'''
pass
def backslash_space():
'\ '
def multiline_backslash_1():
'''
hey\there\
\ '''
def multiline_backslash_2():
'''
hey there \ '''
def multiline_backslash_3():
'''
already escaped \\ '''

View file

@ -0,0 +1,123 @@
class ALonelyClass:
'''
A multiline class docstring.
'''
def AnEquallyLonelyMethod(self):
'''
A multiline method docstring'''
pass
def one_function():
'''This is a docstring with a single line of text.'''
pass
def shockingly_the_quotes_are_normalized():
'''This is a multiline docstring.
This is a multiline docstring.
This is a multiline docstring.
'''
pass
def foo():
"""This is a docstring with
some lines of text here
"""
return
def baz():
'''"This" is a string with some
embedded "quotes"'''
return
def poit():
"""
Lorem ipsum dolor sit amet.
Consectetur adipiscing elit:
- sed do eiusmod tempor incididunt ut labore
- dolore magna aliqua
- enim ad minim veniam
- quis nostrud exercitation ullamco laboris nisi
- aliquip ex ea commodo consequat
"""
pass
def under_indent():
"""
These lines are indented in a way that does not
make sense.
"""
pass
def over_indent():
"""
This has a shallow indent
- But some lines are deeper
- And the closing quote is too deep
"""
pass
def single_line():
"""But with a newline after it!"""
pass
def this():
r"""
'hey ho'
"""
def that():
""" "hey yah" """
def and_that():
"""
"hey yah" """
def and_this():
'''
"hey yah"'''
def believe_it_or_not_this_is_in_the_py_stdlib():
'''
"hey yah"'''
def shockingly_the_quotes_are_normalized_v2():
'''
Docstring Docstring Docstring
'''
pass
def backslash_space():
'\ '
def multiline_backslash_1():
'''
hey\there\
\ '''
def multiline_backslash_2():
'''
hey there \ '''
def multiline_backslash_3():
'''
already escaped \\'''

View file

@ -0,0 +1,10 @@
def do_not_touch_this_prefix():
R"""There was a bug where docstring prefixes would be normalized even with -S."""
def do_not_touch_this_prefix2():
FR'There was a bug where docstring prefixes would be normalized even with -S.'
def do_not_touch_this_prefix3():
u'''There was a bug where docstring prefixes would be normalized even with -S.'''

View file

@ -0,0 +1,10 @@
def do_not_touch_this_prefix():
R"""There was a bug where docstring prefixes would be normalized even with -S."""
def do_not_touch_this_prefix2():
FR'There was a bug where docstring prefixes would be normalized even with -S.'
def do_not_touch_this_prefix3():
u'''There was a bug where docstring prefixes would be normalized even with -S.'''

View file

@ -0,0 +1,3 @@
# The input source must not contain any Py36-specific syntax (e.g. argument type
# annotations, trailing comma after *rest) or this test becomes invalid.
def long_function_name(argument_one, argument_two, argument_three, argument_four, argument_five, argument_six, *rest): ...

View file

@ -0,0 +1,12 @@
# The input source must not contain any Py36-specific syntax (e.g. argument type
# annotations, trailing comma after *rest) or this test becomes invalid.
def long_function_name(
argument_one,
argument_two,
argument_three,
argument_four,
argument_five,
argument_six,
*rest,
):
...

View file

@ -0,0 +1,30 @@
from typing import Union
@bird
def zoo(): ...
class A: ...
@bar
class B:
def BMethod(self) -> None: ...
@overload
def BMethod(self, arg : List[str]) -> None: ...
class C: ...
@hmm
class D: ...
class E: ...
@baz
def foo() -> None:
...
class F (A , C): ...
def spam() -> None: ...
@overload
def spam(arg: str) -> str: ...
var : int = 1
def eggs() -> Union[str, int]: ...

View file

@ -0,0 +1,32 @@
from typing import Union
@bird
def zoo(): ...
class A: ...
@bar
class B:
def BMethod(self) -> None: ...
@overload
def BMethod(self, arg: List[str]) -> None: ...
class C: ...
@hmm
class D: ...
class E: ...
@baz
def foo() -> None: ...
class F(A, C): ...
def spam() -> None: ...
@overload
def spam(arg: str) -> str: ...
var: int = 1
def eggs() -> Union[str, int]: ...

View file

@ -0,0 +1,5 @@
# Regression test for #3427, which reproes only with line length <= 6
def f():
"""
x
"""

View file

@ -0,0 +1,5 @@
# Regression test for #3427, which reproes only with line length <= 6
def f():
"""
x
"""

View file

@ -0,0 +1,292 @@
x = "This is a really long string that can't possibly be expected to fit all together on one line. In fact it may even take up three or more lines... like four or five... but probably just three."
x += "This is a really long string that can't possibly be expected to fit all together on one line. In fact it may even take up three or more lines... like four or five... but probably just three."
y = "Short string"
print(
"This is a really long string inside of a print statement with extra arguments attached at the end of it.",
x,
y,
z,
)
print(
"This is a really long string inside of a print statement with no extra arguments attached at the end of it."
)
D1 = {
"The First": "This is a really long string that can't possibly be expected to fit all together on one line. Also it is inside a dictionary, so formatting is more difficult.",
"The Second": "This is another really really (not really) long string that also can't be expected to fit on one line and is, like the other string, inside a dictionary.",
}
D2 = {
1.0: "This is a really long string that can't possibly be expected to fit all together on one line. Also it is inside a dictionary, so formatting is more difficult.",
2.0: "This is another really really (not really) long string that also can't be expected to fit on one line and is, like the other string, inside a dictionary.",
}
D3 = {
x: "This is a really long string that can't possibly be expected to fit all together on one line. Also it is inside a dictionary, so formatting is more difficult.",
y: "This is another really really (not really) long string that also can't be expected to fit on one line and is, like the other string, inside a dictionary.",
}
D4 = {
"A long and ridiculous {}".format(
string_key
): "This is a really really really long string that has to go i,side of a dictionary. It is soooo bad.",
some_func(
"calling", "some", "stuff"
): "This is a really really really long string that has to go inside of a dictionary. It is {soooo} bad (#{x}).".format(
sooo="soooo", x=2
),
"A %s %s"
% (
"formatted",
"string",
): "This is a really really really long string that has to go inside of a dictionary. It is %s bad (#%d)."
% ("soooo", 2),
}
func_with_keywords(
my_arg,
my_kwarg="Long keyword strings also need to be wrapped, but they will probably need to be handled a little bit differently.",
)
bad_split1 = (
"But what should happen when code has already been formatted but in the wrong way? Like"
" with a space at the end instead of the beginning. Or what about when it is split too soon?"
)
bad_split2 = (
"But what should happen when code has already "
"been formatted but in the wrong way? Like "
"with a space at the end instead of the "
"beginning. Or what about when it is split too "
"soon? In the case of a split that is too "
"short, black will try to honer the custom "
"split."
)
bad_split3 = (
"What if we have inline comments on " # First Comment
"each line of a bad split? In that " # Second Comment
"case, we should just leave it alone." # Third Comment
)
bad_split_func1(
"But what should happen when code has already "
"been formatted but in the wrong way? Like "
"with a space at the end instead of the "
"beginning. Or what about when it is split too "
"soon? In the case of a split that is too "
"short, black will try to honer the custom "
"split.",
xxx,
yyy,
zzz,
)
bad_split_func2(
xxx,
yyy,
zzz,
long_string_kwarg="But what should happen when code has already been formatted but in the wrong way? Like "
"with a space at the end instead of the beginning. Or what about when it is split too "
"soon?",
)
bad_split_func3(
(
"But what should happen when code has already "
r"been formatted but in the wrong way? Like "
"with a space at the end instead of the "
r"beginning. Or what about when it is split too "
r"soon? In the case of a split that is too "
"short, black will try to honer the custom "
"split."
),
xxx,
yyy,
zzz,
)
raw_string = r"This is a long raw string. When re-formatting this string, black needs to make sure it prepends the 'r' onto the new string."
fmt_string1 = "We also need to be sure to preserve any and all {} which may or may not be attached to the string in question.".format(
"method calls"
)
fmt_string2 = "But what about when the string is {} but {}".format(
"short",
"the method call is really really really really really really really really long?",
)
old_fmt_string1 = (
"While we are on the topic of %s, we should also note that old-style formatting must also be preserved, since some %s still uses it."
% ("formatting", "code")
)
old_fmt_string2 = "This is a %s %s %s %s" % (
"really really really really really",
"old",
"way to format strings!",
"Use f-strings instead!",
)
old_fmt_string3 = (
"Whereas only the strings after the percent sign were long in the last example, this example uses a long initial string as well. This is another %s %s %s %s"
% (
"really really really really really",
"old",
"way to format strings!",
"Use f-strings instead!",
)
)
fstring = f"f-strings definitely make things more {difficult} than they need to be for {{black}}. But boy they sure are handy. The problem is that some lines will need to have the 'f' whereas others do not. This {line}, for example, needs one."
fstring_with_no_fexprs = f"Some regular string that needs to get split certainly but is NOT an fstring by any means whatsoever."
comment_string = "Long lines with inline comments should have their comments appended to the reformatted string's enclosing right parentheses." # This comment gets thrown to the top.
arg_comment_string = print(
"Long lines with inline comments which are apart of (and not the only member of) an argument list should have their comments appended to the reformatted string's enclosing left parentheses.", # This comment stays on the bottom.
"Arg #2",
"Arg #3",
"Arg #4",
"Arg #5",
)
pragma_comment_string1 = "Lines which end with an inline pragma comment of the form `# <pragma>: <...>` should be left alone." # noqa: E501
pragma_comment_string2 = "Lines which end with an inline pragma comment of the form `# <pragma>: <...>` should be left alone." # noqa
"""This is a really really really long triple quote string and it should not be touched."""
triple_quote_string = """This is a really really really long triple quote string assignment and it should not be touched."""
assert (
some_type_of_boolean_expression
), "Followed by a really really really long string that is used to provide context to the AssertionError exception."
assert (
some_type_of_boolean_expression
), "Followed by a really really really long string that is used to provide context to the AssertionError exception, which uses dynamic string {}.".format(
"formatting"
)
assert some_type_of_boolean_expression, (
"Followed by a really really really long string that is used to provide context to the AssertionError exception, which uses dynamic string %s."
% "formatting"
)
assert some_type_of_boolean_expression, (
"Followed by a really really really long string that is used to provide context to the AssertionError exception, which uses dynamic %s %s."
% ("string", "formatting")
)
some_function_call(
"With a reallly generic name and with a really really long string that is, at some point down the line, "
+ added
+ " to a variable and then added to another string."
)
some_function_call(
"With a reallly generic name and with a really really long string that is, at some point down the line, "
+ added
+ " to a variable and then added to another string. But then what happens when the final string is also supppppperrrrr long?! Well then that second (realllllllly long) string should be split too.",
"and a second argument",
and_a_third,
)
return "A really really really really really really really really really really really really really long {} {}".format(
"return", "value"
)
func_with_bad_comma(
"This is a really long string argument to a function that has a trailing comma which should NOT be there.",
)
func_with_bad_comma(
"This is a really long string argument to a function that has a trailing comma which should NOT be there.", # comment after comma
)
func_with_bad_comma(
(
"This is a really long string argument to a function that has a trailing comma"
" which should NOT be there."
),
)
func_with_bad_comma(
(
"This is a really long string argument to a function that has a trailing comma"
" which should NOT be there."
), # comment after comma
)
func_with_bad_parens_that_wont_fit_in_one_line(
("short string that should have parens stripped"), x, y, z
)
func_with_bad_parens_that_wont_fit_in_one_line(
x, y, ("short string that should have parens stripped"), z
)
func_with_bad_parens(
("short string that should have parens stripped"),
x,
y,
z,
)
func_with_bad_parens(
x,
y,
("short string that should have parens stripped"),
z,
)
annotated_variable: Final = (
"This is a large "
+ STRING
+ " that has been "
+ CONCATENATED
+ "using the '+' operator."
)
annotated_variable: Final = "This is a large string that has a type annotation attached to it. A type annotation should NOT stop a long string from being wrapped."
annotated_variable: Literal[
"fakse_literal"
] = "This is a large string that has a type annotation attached to it. A type annotation should NOT stop a long string from being wrapped."
backslashes = "This is a really long string with \"embedded\" double quotes and 'single' quotes that also handles checking for an even number of backslashes \\"
backslashes = "This is a really long string with \"embedded\" double quotes and 'single' quotes that also handles checking for an even number of backslashes \\\\"
backslashes = "This is a really 'long' string with \"embedded double quotes\" and 'single' quotes that also handles checking for an odd number of backslashes \\\", like this...\\\\\\"
short_string = "Hi" " there."
func_call(short_string=("Hi" " there."))
raw_strings = r"Don't" " get" r" merged" " unless they are all raw."
def foo():
yield "This is a really long string that can't possibly be expected to fit all together on one line. In fact it may even take up three or more lines... like four or five... but probably just three."
x = f"This is a {{really}} long string that needs to be split without a doubt (i.e. most definitely). In short, this {string} that can't possibly be {{expected}} to fit all together on one line. In {fact} it may even take up three or more lines... like four or five... but probably just four."
long_unmergable_string_with_pragma = (
"This is a really long string that can't be merged because it has a likely pragma at the end" # type: ignore
" of it."
)
long_unmergable_string_with_pragma = (
"This is a really long string that can't be merged because it has a likely pragma at the end" # noqa
" of it."
)
long_unmergable_string_with_pragma = (
"This is a really long string that can't be merged because it has a likely pragma at the end" # pylint: disable=some-pylint-check
" of it."
)

View file

@ -0,0 +1,292 @@
x = "This is a really long string that can't possibly be expected to fit all together on one line. In fact it may even take up three or more lines... like four or five... but probably just three."
x += "This is a really long string that can't possibly be expected to fit all together on one line. In fact it may even take up three or more lines... like four or five... but probably just three."
y = "Short string"
print(
"This is a really long string inside of a print statement with extra arguments attached at the end of it.",
x,
y,
z,
)
print(
"This is a really long string inside of a print statement with no extra arguments attached at the end of it."
)
D1 = {
"The First": "This is a really long string that can't possibly be expected to fit all together on one line. Also it is inside a dictionary, so formatting is more difficult.",
"The Second": "This is another really really (not really) long string that also can't be expected to fit on one line and is, like the other string, inside a dictionary.",
}
D2 = {
1.0: "This is a really long string that can't possibly be expected to fit all together on one line. Also it is inside a dictionary, so formatting is more difficult.",
2.0: "This is another really really (not really) long string that also can't be expected to fit on one line and is, like the other string, inside a dictionary.",
}
D3 = {
x: "This is a really long string that can't possibly be expected to fit all together on one line. Also it is inside a dictionary, so formatting is more difficult.",
y: "This is another really really (not really) long string that also can't be expected to fit on one line and is, like the other string, inside a dictionary.",
}
D4 = {
"A long and ridiculous {}".format(
string_key
): "This is a really really really long string that has to go i,side of a dictionary. It is soooo bad.",
some_func(
"calling", "some", "stuff"
): "This is a really really really long string that has to go inside of a dictionary. It is {soooo} bad (#{x}).".format(
sooo="soooo", x=2
),
"A %s %s"
% (
"formatted",
"string",
): "This is a really really really long string that has to go inside of a dictionary. It is %s bad (#%d)."
% ("soooo", 2),
}
func_with_keywords(
my_arg,
my_kwarg="Long keyword strings also need to be wrapped, but they will probably need to be handled a little bit differently.",
)
bad_split1 = (
"But what should happen when code has already been formatted but in the wrong way? Like"
" with a space at the end instead of the beginning. Or what about when it is split too soon?"
)
bad_split2 = (
"But what should happen when code has already "
"been formatted but in the wrong way? Like "
"with a space at the end instead of the "
"beginning. Or what about when it is split too "
"soon? In the case of a split that is too "
"short, black will try to honer the custom "
"split."
)
bad_split3 = (
"What if we have inline comments on " # First Comment
"each line of a bad split? In that " # Second Comment
"case, we should just leave it alone." # Third Comment
)
bad_split_func1(
"But what should happen when code has already "
"been formatted but in the wrong way? Like "
"with a space at the end instead of the "
"beginning. Or what about when it is split too "
"soon? In the case of a split that is too "
"short, black will try to honer the custom "
"split.",
xxx,
yyy,
zzz,
)
bad_split_func2(
xxx,
yyy,
zzz,
long_string_kwarg="But what should happen when code has already been formatted but in the wrong way? Like "
"with a space at the end instead of the beginning. Or what about when it is split too "
"soon?",
)
bad_split_func3(
(
"But what should happen when code has already "
r"been formatted but in the wrong way? Like "
"with a space at the end instead of the "
r"beginning. Or what about when it is split too "
r"soon? In the case of a split that is too "
"short, black will try to honer the custom "
"split."
),
xxx,
yyy,
zzz,
)
raw_string = r"This is a long raw string. When re-formatting this string, black needs to make sure it prepends the 'r' onto the new string."
fmt_string1 = "We also need to be sure to preserve any and all {} which may or may not be attached to the string in question.".format(
"method calls"
)
fmt_string2 = "But what about when the string is {} but {}".format(
"short",
"the method call is really really really really really really really really long?",
)
old_fmt_string1 = (
"While we are on the topic of %s, we should also note that old-style formatting must also be preserved, since some %s still uses it."
% ("formatting", "code")
)
old_fmt_string2 = "This is a %s %s %s %s" % (
"really really really really really",
"old",
"way to format strings!",
"Use f-strings instead!",
)
old_fmt_string3 = (
"Whereas only the strings after the percent sign were long in the last example, this example uses a long initial string as well. This is another %s %s %s %s"
% (
"really really really really really",
"old",
"way to format strings!",
"Use f-strings instead!",
)
)
fstring = f"f-strings definitely make things more {difficult} than they need to be for {{black}}. But boy they sure are handy. The problem is that some lines will need to have the 'f' whereas others do not. This {line}, for example, needs one."
fstring_with_no_fexprs = f"Some regular string that needs to get split certainly but is NOT an fstring by any means whatsoever."
comment_string = "Long lines with inline comments should have their comments appended to the reformatted string's enclosing right parentheses." # This comment gets thrown to the top.
arg_comment_string = print(
"Long lines with inline comments which are apart of (and not the only member of) an argument list should have their comments appended to the reformatted string's enclosing left parentheses.", # This comment stays on the bottom.
"Arg #2",
"Arg #3",
"Arg #4",
"Arg #5",
)
pragma_comment_string1 = "Lines which end with an inline pragma comment of the form `# <pragma>: <...>` should be left alone." # noqa: E501
pragma_comment_string2 = "Lines which end with an inline pragma comment of the form `# <pragma>: <...>` should be left alone." # noqa
"""This is a really really really long triple quote string and it should not be touched."""
triple_quote_string = """This is a really really really long triple quote string assignment and it should not be touched."""
assert (
some_type_of_boolean_expression
), "Followed by a really really really long string that is used to provide context to the AssertionError exception."
assert (
some_type_of_boolean_expression
), "Followed by a really really really long string that is used to provide context to the AssertionError exception, which uses dynamic string {}.".format(
"formatting"
)
assert some_type_of_boolean_expression, (
"Followed by a really really really long string that is used to provide context to the AssertionError exception, which uses dynamic string %s."
% "formatting"
)
assert some_type_of_boolean_expression, (
"Followed by a really really really long string that is used to provide context to the AssertionError exception, which uses dynamic %s %s."
% ("string", "formatting")
)
some_function_call(
"With a reallly generic name and with a really really long string that is, at some point down the line, "
+ added
+ " to a variable and then added to another string."
)
some_function_call(
"With a reallly generic name and with a really really long string that is, at some point down the line, "
+ added
+ " to a variable and then added to another string. But then what happens when the final string is also supppppperrrrr long?! Well then that second (realllllllly long) string should be split too.",
"and a second argument",
and_a_third,
)
return "A really really really really really really really really really really really really really long {} {}".format(
"return", "value"
)
func_with_bad_comma(
"This is a really long string argument to a function that has a trailing comma which should NOT be there.",
)
func_with_bad_comma(
"This is a really long string argument to a function that has a trailing comma which should NOT be there.", # comment after comma
)
func_with_bad_comma(
(
"This is a really long string argument to a function that has a trailing comma"
" which should NOT be there."
),
)
func_with_bad_comma(
(
"This is a really long string argument to a function that has a trailing comma"
" which should NOT be there."
), # comment after comma
)
func_with_bad_parens_that_wont_fit_in_one_line(
("short string that should have parens stripped"), x, y, z
)
func_with_bad_parens_that_wont_fit_in_one_line(
x, y, ("short string that should have parens stripped"), z
)
func_with_bad_parens(
("short string that should have parens stripped"),
x,
y,
z,
)
func_with_bad_parens(
x,
y,
("short string that should have parens stripped"),
z,
)
annotated_variable: Final = (
"This is a large "
+ STRING
+ " that has been "
+ CONCATENATED
+ "using the '+' operator."
)
annotated_variable: Final = "This is a large string that has a type annotation attached to it. A type annotation should NOT stop a long string from being wrapped."
annotated_variable: Literal[
"fakse_literal"
] = "This is a large string that has a type annotation attached to it. A type annotation should NOT stop a long string from being wrapped."
backslashes = "This is a really long string with \"embedded\" double quotes and 'single' quotes that also handles checking for an even number of backslashes \\"
backslashes = "This is a really long string with \"embedded\" double quotes and 'single' quotes that also handles checking for an even number of backslashes \\\\"
backslashes = "This is a really 'long' string with \"embedded double quotes\" and 'single' quotes that also handles checking for an odd number of backslashes \\\", like this...\\\\\\"
short_string = "Hi" " there."
func_call(short_string=("Hi" " there."))
raw_strings = r"Don't" " get" r" merged" " unless they are all raw."
def foo():
yield "This is a really long string that can't possibly be expected to fit all together on one line. In fact it may even take up three or more lines... like four or five... but probably just three."
x = f"This is a {{really}} long string that needs to be split without a doubt (i.e. most definitely). In short, this {string} that can't possibly be {{expected}} to fit all together on one line. In {fact} it may even take up three or more lines... like four or five... but probably just four."
long_unmergable_string_with_pragma = (
"This is a really long string that can't be merged because it has a likely pragma at the end" # type: ignore
" of it."
)
long_unmergable_string_with_pragma = (
"This is a really long string that can't be merged because it has a likely pragma at the end" # noqa
" of it."
)
long_unmergable_string_with_pragma = (
"This is a really long string that can't be merged because it has a likely pragma at the end" # pylint: disable=some-pylint-check
" of it."
)

View file

@ -0,0 +1,3 @@
# A comment-only file, with no final EOL character
# This triggers https://bugs.python.org/issue2142
# This is the line without the EOL character

View file

@ -0,0 +1,3 @@
# A comment-only file, with no final EOL character
# This triggers https://bugs.python.org/issue2142
# This is the line without the EOL character

View file

@ -0,0 +1 @@
importA;()<<0**0#

View file

@ -0,0 +1,6 @@
importA
(
()
<< 0
** 0
) #

View file

@ -0,0 +1,57 @@
''''''
'\''
'"'
"'"
"\""
"Hello"
"Don't do that"
'Here is a "'
'What\'s the deal here?'
"What's the deal \"here\"?"
"And \"here\"?"
"""Strings with "" in them"""
'''Strings with "" in them'''
'''Here's a "'''
'''Here's a " '''
'''Just a normal triple
quote'''
f"just a normal {f} string"
f'''This is a triple-quoted {f}-string'''
f'MOAR {" ".join([])}'
f"MOAR {' '.join([])}"
r"raw string ftw"
r'Date d\'expiration:(.*)'
r'Tricky "quote'
r'Not-so-tricky \"quote'
rf'{yay}'
'\n\
The \"quick\"\n\
brown fox\n\
jumps over\n\
the \'lazy\' dog.\n\
'
re.compile(r'[\\"]')
"x = ''; y = \"\""
"x = '''; y = \"\""
"x = ''''; y = \"\""
"x = '' ''; y = \"\""
"x = ''; y = \"\"\""
"x = '''; y = \"\"\"\""
"x = ''''; y = \"\"\"\"\""
"x = '' ''; y = \"\"\"\"\""
'unnecessary \"\"escaping'
"unnecessary \'\'escaping"
'\\""'
"\\''"
'Lots of \\\\\\\\\'quotes\''
f'{y * " "} \'{z}\''
f'{{y * " "}} \'{z}\''
f'\'{z}\' {y * " "}'
f'{y * x} \'{z}\''
'\'{z}\' {y * " "}'
'{y * x} \'{z}\''
# We must bail out if changing the quotes would introduce backslashes in f-string
# expressions. xref: https://github.com/psf/black/issues/2348
f"\"{b}\"{' ' * (long-len(b)+1)}: \"{sts}\",\n"
f"\"{a}\"{'hello' * b}\"{c}\""

View file

@ -0,0 +1,52 @@
""""""
"'"
'"'
"'"
'"'
"Hello"
"Don't do that"
'Here is a "'
"What's the deal here?"
'What\'s the deal "here"?'
'And "here"?'
"""Strings with "" in them"""
"""Strings with "" in them"""
'''Here's a "'''
"""Here's a " """
"""Just a normal triple
quote"""
f"just a normal {f} string"
f"""This is a triple-quoted {f}-string"""
f'MOAR {" ".join([])}'
f"MOAR {' '.join([])}"
r"raw string ftw"
r"Date d\'expiration:(.*)"
r'Tricky "quote'
r"Not-so-tricky \"quote"
rf"{yay}"
"\nThe \"quick\"\nbrown fox\njumps over\nthe 'lazy' dog.\n"
re.compile(r'[\\"]')
"x = ''; y = \"\""
"x = '''; y = \"\""
"x = ''''; y = \"\""
"x = '' ''; y = \"\""
'x = \'\'; y = """'
'x = \'\'\'; y = """"'
'x = \'\'\'\'; y = """""'
'x = \'\' \'\'; y = """""'
'unnecessary ""escaping'
"unnecessary ''escaping"
'\\""'
"\\''"
"Lots of \\\\\\\\'quotes'"
f'{y * " "} \'{z}\''
f"{{y * \" \"}} '{z}'"
f'\'{z}\' {y * " "}'
f"{y * x} '{z}'"
"'{z}' {y * \" \"}"
"{y * x} '{z}'"
# We must bail out if changing the quotes would introduce backslashes in f-string
# expressions. xref: https://github.com/psf/black/issues/2348
f"\"{b}\"{' ' * (long-len(b)+1)}: \"{sts}\",\n"
f"\"{a}\"{'hello' * b}\"{c}\""

View file

@ -0,0 +1,21 @@
with (CtxManager() as example):
...
with (CtxManager1(), CtxManager2()):
...
with (CtxManager1() as example, CtxManager2()):
...
with (CtxManager1(), CtxManager2() as example):
...
with (CtxManager1() as example1, CtxManager2() as example2):
...
with (
CtxManager1() as example1,
CtxManager2() as example2,
CtxManager3() as example3,
):
...

View file

@ -0,0 +1,21 @@
with CtxManager() as example:
...
with CtxManager1(), CtxManager2():
...
with CtxManager1() as example, CtxManager2():
...
with CtxManager1(), CtxManager2() as example:
...
with CtxManager1() as example1, CtxManager2() as example2:
...
with (
CtxManager1() as example1,
CtxManager2() as example2,
CtxManager3() as example3,
):
...

View file

@ -0,0 +1,144 @@
# Cases sampled from Lib/test/test_patma.py
# case black_test_patma_098
match x:
case -0j:
y = 0
# case black_test_patma_142
match x:
case bytes(z):
y = 0
# case black_test_patma_073
match x:
case 0 if 0:
y = 0
case 0 if 1:
y = 1
# case black_test_patma_006
match 3:
case 0 | 1 | 2 | 3:
x = True
# case black_test_patma_049
match x:
case [0, 1] | [1, 0]:
y = 0
# case black_check_sequence_then_mapping
match x:
case [*_]:
return "seq"
case {}:
return "map"
# case black_test_patma_035
match x:
case {0: [1, 2, {}]}:
y = 0
case {0: [1, 2, {}] | True} | {1: [[]]} | {0: [1, 2, {}]} | [] | "X" | {}:
y = 1
case []:
y = 2
# case black_test_patma_107
match x:
case 0.25 + 1.75j:
y = 0
# case black_test_patma_097
match x:
case -0j:
y = 0
# case black_test_patma_007
match 4:
case 0 | 1 | 2 | 3:
x = True
# case black_test_patma_154
match x:
case 0 if x:
y = 0
# case black_test_patma_134
match x:
case {1: 0}:
y = 0
case {0: 0}:
y = 1
case {**z}:
y = 2
# case black_test_patma_185
match Seq():
case [*_]:
y = 0
# case black_test_patma_063
match x:
case 1:
y = 0
case 1:
y = 1
# case black_test_patma_248
match x:
case {"foo": bar}:
y = bar
# case black_test_patma_019
match (0, 1, 2):
case [0, 1, *x, 2]:
y = 0
# case black_test_patma_052
match x:
case [0]:
y = 0
case [1, 0] if (x := x[:0]):
y = 1
case [1, 0]:
y = 2
# case black_test_patma_191
match w:
case [x, y, *_]:
z = 0
# case black_test_patma_110
match x:
case -0.25 - 1.75j:
y = 0
# case black_test_patma_151
match (x,):
case [y]:
z = 0
# case black_test_patma_114
match x:
case A.B.C.D:
y = 0
# case black_test_patma_232
match x:
case None:
y = 0
# case black_test_patma_058
match x:
case 0:
y = 0
# case black_test_patma_233
match x:
case False:
y = 0
# case black_test_patma_078
match x:
case []:
y = 0
case [""]:
y = 1
case "":
y = 2
# case black_test_patma_156
match x:
case z:
y = 0
# case black_test_patma_189
match w:
case [x, y, *rest]:
z = 0
# case black_test_patma_042
match x:
case (0 as z) | (1 as z) | (2 as z) if z == x % 2:
y = 0
# case black_test_patma_034
match x:
case {0: [1, 2, {}]}:
y = 0
case {0: [1, 2, {}] | False} | {1: [[]]} | {0: [1, 2, {}]} | [] | "X" | {}:
y = 1
case []:
y = 2

View file

@ -0,0 +1,144 @@
# Cases sampled from Lib/test/test_patma.py
# case black_test_patma_098
match x:
case -0j:
y = 0
# case black_test_patma_142
match x:
case bytes(z):
y = 0
# case black_test_patma_073
match x:
case 0 if 0:
y = 0
case 0 if 1:
y = 1
# case black_test_patma_006
match 3:
case 0 | 1 | 2 | 3:
x = True
# case black_test_patma_049
match x:
case [0, 1] | [1, 0]:
y = 0
# case black_check_sequence_then_mapping
match x:
case [*_]:
return "seq"
case {}:
return "map"
# case black_test_patma_035
match x:
case {0: [1, 2, {}]}:
y = 0
case {0: [1, 2, {}] | True} | {1: [[]]} | {0: [1, 2, {}]} | [] | "X" | {}:
y = 1
case []:
y = 2
# case black_test_patma_107
match x:
case 0.25 + 1.75j:
y = 0
# case black_test_patma_097
match x:
case -0j:
y = 0
# case black_test_patma_007
match 4:
case 0 | 1 | 2 | 3:
x = True
# case black_test_patma_154
match x:
case 0 if x:
y = 0
# case black_test_patma_134
match x:
case {1: 0}:
y = 0
case {0: 0}:
y = 1
case {**z}:
y = 2
# case black_test_patma_185
match Seq():
case [*_]:
y = 0
# case black_test_patma_063
match x:
case 1:
y = 0
case 1:
y = 1
# case black_test_patma_248
match x:
case {"foo": bar}:
y = bar
# case black_test_patma_019
match (0, 1, 2):
case [0, 1, *x, 2]:
y = 0
# case black_test_patma_052
match x:
case [0]:
y = 0
case [1, 0] if (x := x[:0]):
y = 1
case [1, 0]:
y = 2
# case black_test_patma_191
match w:
case [x, y, *_]:
z = 0
# case black_test_patma_110
match x:
case -0.25 - 1.75j:
y = 0
# case black_test_patma_151
match (x,):
case [y]:
z = 0
# case black_test_patma_114
match x:
case A.B.C.D:
y = 0
# case black_test_patma_232
match x:
case None:
y = 0
# case black_test_patma_058
match x:
case 0:
y = 0
# case black_test_patma_233
match x:
case False:
y = 0
# case black_test_patma_078
match x:
case []:
y = 0
case [""]:
y = 1
case "":
y = 2
# case black_test_patma_156
match x:
case z:
y = 0
# case black_test_patma_189
match w:
case [x, y, *rest]:
z = 0
# case black_test_patma_042
match x:
case (0 as z) | (1 as z) | (2 as z) if z == x % 2:
y = 0
# case black_test_patma_034
match x:
case {0: [1, 2, {}]}:
y = 0
case {0: [1, 2, {}] | False} | {1: [[]]} | {0: [1, 2, {}]} | [] | "X" | {}:
y = 1
case []:
y = 2

View file

@ -0,0 +1,119 @@
import match
match something:
case [a as b]:
print(b)
case [a as b, c, d, e as f]:
print(f)
case Point(a as b):
print(b)
case Point(int() as x, int() as y):
print(x, y)
match = 1
case: int = re.match(something)
match re.match(case):
case type("match", match):
pass
case match:
pass
def func(match: case, case: match) -> case:
match Something():
case func(match, case):
...
case another:
...
match maybe, multiple:
case perhaps, 5:
pass
case perhaps, 6,:
pass
match more := (than, one), indeed,:
case _, (5, 6):
pass
case [[5], (6)], [7],:
pass
case _:
pass
match a, *b, c:
case [*_]:
assert "seq" == _
case {}:
assert "map" == b
match match(
case,
match(
match, case, match, looooooooooooooooooooooooooooooooooooong, match, case, match
),
case,
):
case case(
match=case,
case=re.match(
loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong
),
):
pass
case [a as match]:
pass
case case:
pass
match match:
case case:
pass
match a, *b(), c:
case d, *f, g:
pass
match something:
case {
"key": key as key_1,
"password": PASS.ONE | PASS.TWO | PASS.THREE as password,
}:
pass
case {"maybe": something(complicated as this) as that}:
pass
match something:
case 1 as a:
pass
case 2 as b, 3 as c:
pass
case 4 as d, (5 as e), (6 | 7 as g), *h:
pass
match bar1:
case Foo(aa=Callable() as aa, bb=int()):
print(bar1.aa, bar1.bb)
case _:
print("no match", "\n")
match bar1:
case Foo(
normal=x, perhaps=[list, {"x": d, "y": 1.0}] as y, otherwise=something, q=t as u
):
pass

View file

@ -0,0 +1,119 @@
import match
match something:
case [a as b]:
print(b)
case [a as b, c, d, e as f]:
print(f)
case Point(a as b):
print(b)
case Point(int() as x, int() as y):
print(x, y)
match = 1
case: int = re.match(something)
match re.match(case):
case type("match", match):
pass
case match:
pass
def func(match: case, case: match) -> case:
match Something():
case func(match, case):
...
case another:
...
match maybe, multiple:
case perhaps, 5:
pass
case perhaps, 6,:
pass
match more := (than, one), indeed,:
case _, (5, 6):
pass
case [[5], (6)], [7],:
pass
case _:
pass
match a, *b, c:
case [*_]:
assert "seq" == _
case {}:
assert "map" == b
match match(
case,
match(
match, case, match, looooooooooooooooooooooooooooooooooooong, match, case, match
),
case,
):
case case(
match=case,
case=re.match(
loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong
),
):
pass
case [a as match]:
pass
case case:
pass
match match:
case case:
pass
match a, *b(), c:
case d, *f, g:
pass
match something:
case {
"key": key as key_1,
"password": PASS.ONE | PASS.TWO | PASS.THREE as password,
}:
pass
case {"maybe": something(complicated as this) as that}:
pass
match something:
case 1 as a:
pass
case 2 as b, 3 as c:
pass
case 4 as d, (5 as e), (6 | 7 as g), *h:
pass
match bar1:
case Foo(aa=Callable() as aa, bb=int()):
print(bar1.aa, bar1.bb)
case _:
print("no match", "\n")
match bar1:
case Foo(
normal=x, perhaps=[list, {"x": d, "y": 1.0}] as y, otherwise=something, q=t as u
):
pass

View file

@ -0,0 +1,107 @@
re.match()
match = a
with match() as match:
match = f"{match}"
re.match()
match = a
with match() as match:
match = f"{match}"
def get_grammars(target_versions: Set[TargetVersion]) -> List[Grammar]:
if not target_versions:
# No target_version specified, so try all grammars.
return [
# Python 3.7+
pygram.python_grammar_no_print_statement_no_exec_statement_async_keywords,
# Python 3.0-3.6
pygram.python_grammar_no_print_statement_no_exec_statement,
# Python 2.7 with future print_function import
pygram.python_grammar_no_print_statement,
# Python 2.7
pygram.python_grammar,
]
match match:
case case:
match match:
case case:
pass
if all(version.is_python2() for version in target_versions):
# Python 2-only code, so try Python 2 grammars.
return [
# Python 2.7 with future print_function import
pygram.python_grammar_no_print_statement,
# Python 2.7
pygram.python_grammar,
]
re.match()
match = a
with match() as match:
match = f"{match}"
def test_patma_139(self):
x = False
match x:
case bool(z):
y = 0
self.assertIs(x, False)
self.assertEqual(y, 0)
self.assertIs(z, x)
# Python 3-compatible code, so only try Python 3 grammar.
grammars = []
if supports_feature(target_versions, Feature.PATTERN_MATCHING):
# Python 3.10+
grammars.append(pygram.python_grammar_soft_keywords)
# If we have to parse both, try to parse async as a keyword first
if not supports_feature(
target_versions, Feature.ASYNC_IDENTIFIERS
) and not supports_feature(target_versions, Feature.PATTERN_MATCHING):
# Python 3.7-3.9
grammars.append(
pygram.python_grammar_no_print_statement_no_exec_statement_async_keywords
)
if not supports_feature(target_versions, Feature.ASYNC_KEYWORDS):
# Python 3.0-3.6
grammars.append(pygram.python_grammar_no_print_statement_no_exec_statement)
def test_patma_155(self):
x = 0
y = None
match x:
case 1e1000:
y = 0
self.assertEqual(x, 0)
self.assertIs(y, None)
x = range(3)
match x:
case [y, case as x, z]:
w = 0
# At least one of the above branches must have been taken, because every Python
# version has exactly one of the two 'ASYNC_*' flags
return grammars
def lib2to3_parse(src_txt: str, target_versions: Iterable[TargetVersion] = ()) -> Node:
"""Given a string with source, return the lib2to3 Node."""
if not src_txt.endswith("\n"):
src_txt += "\n"
grammars = get_grammars(set(target_versions))
re.match()
match = a
with match() as match:
match = f"{match}"
re.match()
match = a
with match() as match:
match = f"{match}"

View file

@ -0,0 +1,107 @@
re.match()
match = a
with match() as match:
match = f"{match}"
re.match()
match = a
with match() as match:
match = f"{match}"
def get_grammars(target_versions: Set[TargetVersion]) -> List[Grammar]:
if not target_versions:
# No target_version specified, so try all grammars.
return [
# Python 3.7+
pygram.python_grammar_no_print_statement_no_exec_statement_async_keywords,
# Python 3.0-3.6
pygram.python_grammar_no_print_statement_no_exec_statement,
# Python 2.7 with future print_function import
pygram.python_grammar_no_print_statement,
# Python 2.7
pygram.python_grammar,
]
match match:
case case:
match match:
case case:
pass
if all(version.is_python2() for version in target_versions):
# Python 2-only code, so try Python 2 grammars.
return [
# Python 2.7 with future print_function import
pygram.python_grammar_no_print_statement,
# Python 2.7
pygram.python_grammar,
]
re.match()
match = a
with match() as match:
match = f"{match}"
def test_patma_139(self):
x = False
match x:
case bool(z):
y = 0
self.assertIs(x, False)
self.assertEqual(y, 0)
self.assertIs(z, x)
# Python 3-compatible code, so only try Python 3 grammar.
grammars = []
if supports_feature(target_versions, Feature.PATTERN_MATCHING):
# Python 3.10+
grammars.append(pygram.python_grammar_soft_keywords)
# If we have to parse both, try to parse async as a keyword first
if not supports_feature(
target_versions, Feature.ASYNC_IDENTIFIERS
) and not supports_feature(target_versions, Feature.PATTERN_MATCHING):
# Python 3.7-3.9
grammars.append(
pygram.python_grammar_no_print_statement_no_exec_statement_async_keywords
)
if not supports_feature(target_versions, Feature.ASYNC_KEYWORDS):
# Python 3.0-3.6
grammars.append(pygram.python_grammar_no_print_statement_no_exec_statement)
def test_patma_155(self):
x = 0
y = None
match x:
case 1e1000:
y = 0
self.assertEqual(x, 0)
self.assertIs(y, None)
x = range(3)
match x:
case [y, case as x, z]:
w = 0
# At least one of the above branches must have been taken, because every Python
# version has exactly one of the two 'ASYNC_*' flags
return grammars
def lib2to3_parse(src_txt: str, target_versions: Iterable[TargetVersion] = ()) -> Node:
"""Given a string with source, return the lib2to3 Node."""
if not src_txt.endswith("\n"):
src_txt += "\n"
grammars = get_grammars(set(target_versions))
re.match()
match = a
with match() as match:
match = f"{match}"
re.match()
match = a
with match() as match:
match = f"{match}"

View file

@ -0,0 +1,92 @@
# Cases sampled from PEP 636 examples
match command.split():
case [action, obj]:
... # interpret action, obj
match command.split():
case [action]:
... # interpret single-verb action
case [action, obj]:
... # interpret action, obj
match command.split():
case ["quit"]:
print("Goodbye!")
quit_game()
case ["look"]:
current_room.describe()
case ["get", obj]:
character.get(obj, current_room)
case ["go", direction]:
current_room = current_room.neighbor(direction)
# The rest of your commands go here
match command.split():
case ["drop", *objects]:
for obj in objects:
character.drop(obj, current_room)
# The rest of your commands go here
match command.split():
case ["quit"]:
pass
case ["go", direction]:
print("Going:", direction)
case ["drop", *objects]:
print("Dropping: ", *objects)
case _:
print(f"Sorry, I couldn't understand {command!r}")
match command.split():
case ["north"] | ["go", "north"]:
current_room = current_room.neighbor("north")
case ["get", obj] | ["pick", "up", obj] | ["pick", obj, "up"]:
... # Code for picking up the given object
match command.split():
case ["go", ("north" | "south" | "east" | "west")]:
current_room = current_room.neighbor(...)
# how do I know which direction to go?
match command.split():
case ["go", ("north" | "south" | "east" | "west") as direction]:
current_room = current_room.neighbor(direction)
match command.split():
case ["go", direction] if direction in current_room.exits:
current_room = current_room.neighbor(direction)
case ["go", _]:
print("Sorry, you can't go that way")
match event.get():
case Click(position=(x, y)):
handle_click_at(x, y)
case KeyPress(key_name="Q") | Quit():
game.quit()
case KeyPress(key_name="up arrow"):
game.go_north()
case KeyPress():
pass # Ignore other keystrokes
case other_event:
raise ValueError(f"Unrecognized event: {other_event}")
match event.get():
case Click((x, y), button=Button.LEFT): # This is a left click
handle_click_at(x, y)
case Click():
pass # ignore other clicks
def where_is(point):
match point:
case Point(x=0, y=0):
print("Origin")
case Point(x=0, y=y):
print(f"Y={y}")
case Point(x=x, y=0):
print(f"X={x}")
case Point():
print("Somewhere else")
case _:
print("Not a point")

View file

@ -0,0 +1,92 @@
# Cases sampled from PEP 636 examples
match command.split():
case [action, obj]:
... # interpret action, obj
match command.split():
case [action]:
... # interpret single-verb action
case [action, obj]:
... # interpret action, obj
match command.split():
case ["quit"]:
print("Goodbye!")
quit_game()
case ["look"]:
current_room.describe()
case ["get", obj]:
character.get(obj, current_room)
case ["go", direction]:
current_room = current_room.neighbor(direction)
# The rest of your commands go here
match command.split():
case ["drop", *objects]:
for obj in objects:
character.drop(obj, current_room)
# The rest of your commands go here
match command.split():
case ["quit"]:
pass
case ["go", direction]:
print("Going:", direction)
case ["drop", *objects]:
print("Dropping: ", *objects)
case _:
print(f"Sorry, I couldn't understand {command!r}")
match command.split():
case ["north"] | ["go", "north"]:
current_room = current_room.neighbor("north")
case ["get", obj] | ["pick", "up", obj] | ["pick", obj, "up"]:
... # Code for picking up the given object
match command.split():
case ["go", ("north" | "south" | "east" | "west")]:
current_room = current_room.neighbor(...)
# how do I know which direction to go?
match command.split():
case ["go", ("north" | "south" | "east" | "west") as direction]:
current_room = current_room.neighbor(direction)
match command.split():
case ["go", direction] if direction in current_room.exits:
current_room = current_room.neighbor(direction)
case ["go", _]:
print("Sorry, you can't go that way")
match event.get():
case Click(position=(x, y)):
handle_click_at(x, y)
case KeyPress(key_name="Q") | Quit():
game.quit()
case KeyPress(key_name="up arrow"):
game.go_north()
case KeyPress():
pass # Ignore other keystrokes
case other_event:
raise ValueError(f"Unrecognized event: {other_event}")
match event.get():
case Click((x, y), button=Button.LEFT): # This is a left click
handle_click_at(x, y)
case Click():
pass # ignore other clicks
def where_is(point):
match point:
case Point(x=0, y=0):
print("Origin")
case Point(x=0, y=y):
print(f"Y={y}")
case Point(x=x, y=0):
print(f"X={x}")
case Point():
print("Somewhere else")
case _:
print("Not a point")

View file

@ -0,0 +1,53 @@
match something:
case b(): print(1+1)
case c(
very_complex=True,
perhaps_even_loooooooooooooooooooooooooooooooooooooong=- 1
): print(1)
case c(
very_complex=True,
perhaps_even_loooooooooooooooooooooooooooooooooooooong=-1,
): print(2)
case a: pass
match(
arg # comment
)
match(
)
match(
)
case(
arg # comment
)
case(
)
case(
)
re.match(
something # fast
)
re.match(
)
match match(
):
case case(
arg, # comment
):
pass

View file

@ -0,0 +1,35 @@
match something:
case b():
print(1 + 1)
case c(
very_complex=True, perhaps_even_loooooooooooooooooooooooooooooooooooooong=-1
):
print(1)
case c(
very_complex=True,
perhaps_even_loooooooooooooooooooooooooooooooooooooong=-1,
):
print(2)
case a:
pass
match(arg) # comment
match()
match()
case(arg) # comment
case()
case()
re.match(something) # fast
re.match()
match match():
case case(
arg, # comment
):
pass

View file

@ -0,0 +1,15 @@
# Unparenthesized walruses are now allowed in indices since Python 3.10.
x[a:=0]
x[a:=0, b:=1]
x[5, b:=0]
# Walruses are allowed inside generator expressions on function calls since 3.10.
if any(match := pattern_error.match(s) for s in buffer):
if match.group(2) == data_not_available:
# Error OK to ignore.
pass
f(a := b + c for c in range(10))
f((a := b + c for c in range(10)), x)
f(y=(a := b + c for c in range(10)))
f(x, (a := b + c for c in range(10)), y=z, **q)

View file

@ -0,0 +1,15 @@
# Unparenthesized walruses are now allowed in indices since Python 3.10.
x[a:=0]
x[a:=0, b:=1]
x[5, b:=0]
# Walruses are allowed inside generator expressions on function calls since 3.10.
if any(match := pattern_error.match(s) for s in buffer):
if match.group(2) == data_not_available:
# Error OK to ignore.
pass
f(a := b + c for c in range(10))
f((a := b + c for c in range(10)), x)
f(y=(a := b + c for c in range(10)))
f(x, (a := b + c for c in range(10)), y=z, **q)

View file

@ -0,0 +1,19 @@
def http_status(status):
match status:
case 400:
return "Bad request"
case 401:
return "Unauthorized"
case 403:
return "Forbidden"
case 404:
return "Not found"

View file

@ -0,0 +1,13 @@
def http_status(status):
match status:
case 400:
return "Bad request"
case 401:
return "Unauthorized"
case 403:
return "Forbidden"
case 404:
return "Not found"

View file

@ -0,0 +1,27 @@
for x in *a, *b:
print(x)
for x in a, b, *c:
print(x)
for x in *a, b, c:
print(x)
for x in *a, b, *c:
print(x)
async for x in *a, *b:
print(x)
async for x in *a, b, *c:
print(x)
async for x in a, b, *c:
print(x)
async for x in (
*loooooooooooooooooooooong,
very,
*loooooooooooooooooooooooooooooooooooooooooooooooong,
):
print(x)

View file

@ -0,0 +1,27 @@
for x in *a, *b:
print(x)
for x in a, b, *c:
print(x)
for x in *a, b, c:
print(x)
for x in *a, b, *c:
print(x)
async for x in *a, *b:
print(x)
async for x in *a, b, *c:
print(x)
async for x in a, b, *c:
print(x)
async for x in (
*loooooooooooooooooooooong,
very,
*loooooooooooooooooooooooooooooooooooooooooooooooong,
):
print(x)

View file

@ -0,0 +1,53 @@
try:
raise OSError("blah")
except* ExceptionGroup as e:
pass
try:
async with trio.open_nursery() as nursery:
# Make two concurrent calls to child()
nursery.start_soon(child)
nursery.start_soon(child)
except* ValueError:
pass
try:
try:
raise ValueError(42)
except:
try:
raise TypeError(int)
except* Exception:
pass
1 / 0
except Exception as e:
exc = e
try:
try:
raise FalsyEG("eg", [TypeError(1), ValueError(2)])
except* TypeError as e:
tes = e
raise
except* ValueError as e:
ves = e
pass
except Exception as e:
exc = e
try:
try:
raise orig
except* (TypeError, ValueError) as e:
raise SyntaxError(3) from e
except BaseException as e:
exc = e
try:
try:
raise orig
except* OSError as e:
raise TypeError(3) from e
except ExceptionGroup as e:
exc = e

View file

@ -0,0 +1,53 @@
try:
raise OSError("blah")
except* ExceptionGroup as e:
pass
try:
async with trio.open_nursery() as nursery:
# Make two concurrent calls to child()
nursery.start_soon(child)
nursery.start_soon(child)
except* ValueError:
pass
try:
try:
raise ValueError(42)
except:
try:
raise TypeError(int)
except* Exception:
pass
1 / 0
except Exception as e:
exc = e
try:
try:
raise FalsyEG("eg", [TypeError(1), ValueError(2)])
except* TypeError as e:
tes = e
raise
except* ValueError as e:
ves = e
pass
except Exception as e:
exc = e
try:
try:
raise orig
except* (TypeError, ValueError) as e:
raise SyntaxError(3) from e
except BaseException as e:
exc = e
try:
try:
raise orig
except* OSError as e:
raise TypeError(3) from e
except ExceptionGroup as e:
exc = e

View file

@ -0,0 +1,55 @@
try:
raise OSError("blah")
except * ExceptionGroup as e:
pass
try:
async with trio.open_nursery() as nursery:
# Make two concurrent calls to child()
nursery.start_soon(child)
nursery.start_soon(child)
except *ValueError:
pass
try:
try:
raise ValueError(42)
except:
try:
raise TypeError(int)
except *(Exception):
pass
1 / 0
except Exception as e:
exc = e
try:
try:
raise FalsyEG("eg", [TypeError(1), ValueError(2)])
except \
*TypeError as e:
tes = e
raise
except * ValueError as e:
ves = e
pass
except Exception as e:
exc = e
try:
try:
raise orig
except *(TypeError, ValueError, *OTHER_EXCEPTIONS) as e:
raise SyntaxError(3) from e
except BaseException as e:
exc = e
try:
try:
raise orig
except\
* OSError as e:
raise TypeError(3) from e
except ExceptionGroup as e:
exc = e

View file

@ -0,0 +1,53 @@
try:
raise OSError("blah")
except* ExceptionGroup as e:
pass
try:
async with trio.open_nursery() as nursery:
# Make two concurrent calls to child()
nursery.start_soon(child)
nursery.start_soon(child)
except* ValueError:
pass
try:
try:
raise ValueError(42)
except:
try:
raise TypeError(int)
except* Exception:
pass
1 / 0
except Exception as e:
exc = e
try:
try:
raise FalsyEG("eg", [TypeError(1), ValueError(2)])
except* TypeError as e:
tes = e
raise
except* ValueError as e:
ves = e
pass
except Exception as e:
exc = e
try:
try:
raise orig
except* (TypeError, ValueError, *OTHER_EXCEPTIONS) as e:
raise SyntaxError(3) from e
except BaseException as e:
exc = e
try:
try:
raise orig
except* OSError as e:
raise TypeError(3) from e
except ExceptionGroup as e:
exc = e

View file

@ -0,0 +1,20 @@
#!/usr/bin/env python3.6
x = 123456789
x = 123456
x = .1
x = 1.
x = 1E+1
x = 1E-1
x = 1.000_000_01
x = 123456789.123456789
x = 123456789.123456789E123456789
x = 123456789E123456789
x = 123456789J
x = 123456789.123456789J
x = 0XB1ACC
x = 0B1011
x = 0O777
x = 0.000000006
x = 10000
x = 133333

View file

@ -0,0 +1,20 @@
#!/usr/bin/env python3.6
x = 123456789
x = 123456
x = 0.1
x = 1.0
x = 1e1
x = 1e-1
x = 1.000_000_01
x = 123456789.123456789
x = 123456789.123456789e123456789
x = 123456789e123456789
x = 123456789j
x = 123456789.123456789j
x = 0xB1ACC
x = 0b1011
x = 0o777
x = 0.000000006
x = 10000
x = 133333

View file

@ -0,0 +1,10 @@
#!/usr/bin/env python3.6
x = 123456789
x = 1_2_3_4_5_6_7
x = 1E+1
x = 0xb1acc
x = 0.00_00_006
x = 12_34_567J
x = .1_2
x = 1_2.

View file

@ -0,0 +1,10 @@
#!/usr/bin/env python3.6
x = 123456789
x = 1_2_3_4_5_6_7
x = 1e1
x = 0xB1ACC
x = 0.00_00_006
x = 12_34_567j
x = 0.1_2
x = 1_2.0

View file

@ -0,0 +1,30 @@
#!/usr/bin/env python3.7
def f():
return (i * 2 async for i in arange(42))
def g():
return (
something_long * something_long
async for something_long in async_generator(with_an_argument)
)
async def func():
if test:
out_batched = [
i
async for i in aitertools._async_map(
self.async_inc, arange(8), batch_size=3
)
]
def awaited_generator_value(n):
return (await awaitable for awaitable in awaitable_list)
def make_arange(n):
return (i * 2 for i in range(n) if await wrap(i))

View file

@ -0,0 +1,30 @@
#!/usr/bin/env python3.7
def f():
return (i * 2 async for i in arange(42))
def g():
return (
something_long * something_long
async for something_long in async_generator(with_an_argument)
)
async def func():
if test:
out_batched = [
i
async for i in aitertools._async_map(
self.async_inc, arange(8), batch_size=3
)
]
def awaited_generator_value(n):
return (await awaitable for awaitable in awaitable_list)
def make_arange(n):
return (i * 2 for i in range(n) if await wrap(i))

View file

@ -0,0 +1,44 @@
def positional_only_arg(a, /):
pass
def all_markers(a, b, /, c, d, *, e, f):
pass
def all_markers_with_args_and_kwargs(
a_long_one,
b_long_one,
/,
c_long_one,
d_long_one,
*args,
e_long_one,
f_long_one,
**kwargs,
):
pass
def all_markers_with_defaults(a, b=1, /, c=2, d=3, *, e=4, f=5):
pass
def long_one_with_long_parameter_names(
but_all_of_them,
are_positional_only,
arguments_mmmmkay,
so_this_is_only_valid_after,
three_point_eight,
/,
):
pass
lambda a, /: a
lambda a, b, /, c, d, *, e, f: a
lambda a, b, /, c, d, *args, e, f, **kwargs: args
lambda a, b=1, /, c=2, d=3, *, e=4, f=5: 1

View file

@ -0,0 +1,44 @@
def positional_only_arg(a, /):
pass
def all_markers(a, b, /, c, d, *, e, f):
pass
def all_markers_with_args_and_kwargs(
a_long_one,
b_long_one,
/,
c_long_one,
d_long_one,
*args,
e_long_one,
f_long_one,
**kwargs,
):
pass
def all_markers_with_defaults(a, b=1, /, c=2, d=3, *, e=4, f=5):
pass
def long_one_with_long_parameter_names(
but_all_of_them,
are_positional_only,
arguments_mmmmkay,
so_this_is_only_valid_after,
three_point_eight,
/,
):
pass
lambda a, /: a
lambda a, b, /, c, d, *, e, f: a
lambda a, b, /, c, d, *args, e, f, **kwargs: args
lambda a, b=1, /, c=2, d=3, *, e=4, f=5: 1

View file

@ -0,0 +1,47 @@
(a := 1)
(a := a)
if (match := pattern.search(data)) is None:
pass
if match := pattern.search(data):
pass
[y := f(x), y**2, y**3]
filtered_data = [y for x in data if (y := f(x)) is None]
(y := f(x))
y0 = (y1 := f(x))
foo(x=(y := f(x)))
def foo(answer=(p := 42)):
pass
def foo(answer: (p := 42) = 5):
pass
lambda: (x := 1)
(x := lambda: 1)
(x := lambda: (y := 1))
lambda line: (m := re.match(pattern, line)) and m.group(1)
x = (y := 0)
(z := (y := (x := 0)))
(info := (name, phone, *rest))
(x := 1, 2)
(total := total + tax)
len(lines := f.readlines())
foo(x := 3, cat="vector")
foo(cat=(category := "vector"))
if any(len(longline := l) >= 100 for l in lines):
print(longline)
if env_base := os.environ.get("PYTHONUSERBASE", None):
return env_base
if self._is_special and (ans := self._check_nans(context=context)):
return ans
foo(b := 2, a=1)
foo((b := 2), a=1)
foo(c=(b := 2), a=1)
while x := f(x):
pass
while x := f(x):
pass

View file

@ -0,0 +1,47 @@
(a := 1)
(a := a)
if (match := pattern.search(data)) is None:
pass
if match := pattern.search(data):
pass
[y := f(x), y**2, y**3]
filtered_data = [y for x in data if (y := f(x)) is None]
(y := f(x))
y0 = (y1 := f(x))
foo(x=(y := f(x)))
def foo(answer=(p := 42)):
pass
def foo(answer: (p := 42) = 5):
pass
lambda: (x := 1)
(x := lambda: 1)
(x := lambda: (y := 1))
lambda line: (m := re.match(pattern, line)) and m.group(1)
x = (y := 0)
(z := (y := (x := 0)))
(info := (name, phone, *rest))
(x := 1, 2)
(total := total + tax)
len(lines := f.readlines())
foo(x := 3, cat="vector")
foo(cat=(category := "vector"))
if any(len(longline := l) >= 100 for l in lines):
print(longline)
if env_base := os.environ.get("PYTHONUSERBASE", None):
return env_base
if self._is_special and (ans := self._check_nans(context=context)):
return ans
foo(b := 2, a=1)
foo((b := 2), a=1)
foo(c=(b := 2), a=1)
while x := f(x):
pass
while x := f(x):
pass

View file

@ -0,0 +1,19 @@
#!/usr/bin/env python3.8
def starred_return():
my_list = ["value2", "value3"]
return "value1", *my_list
def starred_yield():
my_list = ["value2", "value3"]
yield "value1", *my_list
# all right hand side expressions allowed in regular assignments are now also allowed in
# annotated assignments
a : Tuple[ str, int] = "1", 2
a: Tuple[int , ... ] = b, *c, d
def t():
a : str = yield "a"

View file

@ -0,0 +1,21 @@
#!/usr/bin/env python3.8
def starred_return():
my_list = ["value2", "value3"]
return "value1", *my_list
def starred_yield():
my_list = ["value2", "value3"]
yield "value1", *my_list
# all right hand side expressions allowed in regular assignments are now also allowed in
# annotated assignments
a: Tuple[str, int] = "1", 2
a: Tuple[int, ...] = b, *c, d
def t():
a: str = yield "a"

View file

@ -0,0 +1,7 @@
# Unparenthesized walruses are now allowed in set literals & set comprehensions
# since Python 3.9
{x := 1, 2, 3}
{x4 := x**5 for x in range(7)}
# We better not remove the parentheses here (since it's a 3.10 feature)
x[(a := 1)]
x[(a := 1), (b := 3)]

View file

@ -0,0 +1,7 @@
# Unparenthesized walruses are now allowed in set literals & set comprehensions
# since Python 3.9
{x := 1, 2, 3}
{x4 := x**5 for x in range(7)}
# We better not remove the parentheses here (since it's a 3.10 feature)
x[(a := 1)]
x[(a := 1), (b := 3)]

View file

@ -0,0 +1,13 @@
#!/usr/bin/env python3.9
@relaxed_decorator[0]
def f():
...
@relaxed_decorator[extremely_long_name_that_definitely_will_not_fit_on_one_line_of_standard_length]
def f():
...
@extremely_long_variable_name_that_doesnt_fit := complex.expression(with_long="arguments_value_that_wont_fit_at_the_end_of_the_line")
def f():
...

View file

@ -0,0 +1,20 @@
#!/usr/bin/env python3.9
@relaxed_decorator[0]
def f():
...
@relaxed_decorator[
extremely_long_name_that_definitely_will_not_fit_on_one_line_of_standard_length
]
def f():
...
@extremely_long_variable_name_that_doesnt_fit := complex.expression(
with_long="arguments_value_that_wont_fit_at_the_end_of_the_line"
)
def f():
...

View file

@ -0,0 +1,54 @@
with (open("bla.txt")):
pass
with (open("bla.txt")), (open("bla.txt")):
pass
with (open("bla.txt") as f):
pass
# Remove brackets within alias expression
with (open("bla.txt")) as f:
pass
# Remove brackets around one-line context managers
with (open("bla.txt") as f, (open("x"))):
pass
with ((open("bla.txt")) as f, open("x")):
pass
with (CtxManager1() as example1, CtxManager2() as example2):
...
# Brackets remain when using magic comma
with (CtxManager1() as example1, CtxManager2() as example2,):
...
# Brackets remain for multi-line context managers
with (CtxManager1() as example1, CtxManager2() as example2, CtxManager2() as example2, CtxManager2() as example2, CtxManager2() as example2):
...
# Don't touch assignment expressions
with (y := open("./test.py")) as f:
pass
# Deeply nested examples
# N.B. Multiple brackets are only possible
# around the context manager itself.
# Only one brackets is allowed around the
# alias expression or comma-delimited context managers.
with (((open("bla.txt")))):
pass
with (((open("bla.txt")))), (((open("bla.txt")))):
pass
with (((open("bla.txt")))) as f:
pass
with ((((open("bla.txt")))) as f):
pass
with ((((CtxManager1()))) as example1, (((CtxManager2()))) as example2):
...

View file

@ -0,0 +1,63 @@
with open("bla.txt"):
pass
with open("bla.txt"), open("bla.txt"):
pass
with open("bla.txt") as f:
pass
# Remove brackets within alias expression
with open("bla.txt") as f:
pass
# Remove brackets around one-line context managers
with open("bla.txt") as f, open("x"):
pass
with open("bla.txt") as f, open("x"):
pass
with CtxManager1() as example1, CtxManager2() as example2:
...
# Brackets remain when using magic comma
with (
CtxManager1() as example1,
CtxManager2() as example2,
):
...
# Brackets remain for multi-line context managers
with (
CtxManager1() as example1,
CtxManager2() as example2,
CtxManager2() as example2,
CtxManager2() as example2,
CtxManager2() as example2,
):
...
# Don't touch assignment expressions
with (y := open("./test.py")) as f:
pass
# Deeply nested examples
# N.B. Multiple brackets are only possible
# around the context manager itself.
# Only one brackets is allowed around the
# alias expression or comma-delimited context managers.
with open("bla.txt"):
pass
with open("bla.txt"), open("bla.txt"):
pass
with open("bla.txt") as f:
pass
with open("bla.txt") as f:
pass
with CtxManager1() as example1, CtxManager2() as example2:
...

View file

@ -93,4 +93,4 @@ async def wat():
# Some closing comments.
# Maybe Vim or Emacs directives for formatting.
# Who knows.
# Who knows.

View file

@ -1,3 +1,4 @@
...
"some_string"
b"\\xa3"
Name
@ -114,7 +115,7 @@ call(
arg,
another,
kwarg="hey",
**kwargs,
**kwargs
) # note: no trailing comma pre-3.6
call(*gidgets[:2])
call(a, *gidgets[:2])

View file

@ -5,7 +5,6 @@ import sys
from third_party import X, Y, Z
from library import some_connection, some_decorator
# fmt: off
from third_party import (X,
Y, Z)

View file

@ -0,0 +1,19 @@
# Regression test for https://github.com/psf/black/issues/3438
import ast
import collections # fmt: skip
import dataclasses
# fmt: off
import os
# fmt: on
import pathlib
import re # fmt: skip
import secrets
# fmt: off
import sys
# fmt: on
import tempfile
import zoneinfo

View file

@ -0,0 +1,19 @@
# Regression test for https://github.com/psf/black/issues/3438
import ast
import collections # fmt: skip
import dataclasses
# fmt: off
import os
# fmt: on
import pathlib
import re # fmt: skip
import secrets
# fmt: off
import sys
# fmt: on
import tempfile
import zoneinfo

View file

@ -7,3 +7,5 @@ f"{f'''{'nested'} inner'''} outer"
f"\"{f'{nested} inner'}\" outer"
f"space between opening braces: { {a for a in (1, 2, 3)}}"
f'Hello \'{tricky + "example"}\''
f"Tried directories {str(rootdirs)} \
but none started with prefix {parentdir_prefix}"

View file

@ -7,3 +7,5 @@ f"{f'''{'nested'} inner'''} outer"
f"\"{f'{nested} inner'}\" outer"
f"space between opening braces: { {a for a in (1, 2, 3)}}"
f'Hello \'{tricky + "example"}\''
f"Tried directories {str(rootdirs)} \
but none started with prefix {parentdir_prefix}"

View file

@ -34,7 +34,7 @@ def spaces(a=1, b=(), c=[], d={}, e=True, f=-1, g=1 if False else 2, h="", i=r''
def spaces_types(a: int = 1, b: tuple = (), c: list = [], d: dict = {}, e: bool = True, f: int = -1, g: int = 1 if False else 2, h: str = "", i: str = r''): ...
def spaces2(result= _core.Value(None)):
assert fut is self._read_fut, (fut, self._read_fut)
# EMPTY LINE WITH WHITESPACE (this comment will be removed)
def example(session):
result = session.query(models.Customer.id).filter(
models.Customer.account_id == account_id,

View file

@ -0,0 +1,6 @@
def some_very_long_name_function() -> my_module.Asdf | my_module.AnotherType | my_module.YetAnotherType | None:
pass
def some_very_long_name_function() -> my_module.Asdf | my_module.AnotherType | my_module.YetAnotherType | my_module.EvenMoreType | None:
pass

View file

@ -0,0 +1,14 @@
def some_very_long_name_function() -> (
my_module.Asdf | my_module.AnotherType | my_module.YetAnotherType | None
):
pass
def some_very_long_name_function() -> (
my_module.Asdf
| my_module.AnotherType
| my_module.YetAnotherType
| my_module.EvenMoreType
| None
):
pass

View file

@ -29,35 +29,3 @@ ham[lower:upper], ham[lower:upper:], ham[lower::step]
# ham[lower+offset : upper+offset]
ham[: upper_fn(x) : step_fn(x)], ham[:: step_fn(x)]
ham[lower + offset : upper + offset]
slice[::, ::]
slice[
# A
:
# B
:
# C
]
slice[
# A
1:
# B
2:
# C
3
]
slice[
# A
1
+ 2 :
# B
3 :
# C
4
]
x[
1: # A
2: # B
3 # C
]

View file

@ -29,31 +29,3 @@ ham[lower:upper], ham[lower:upper:], ham[lower::step]
# ham[lower+offset : upper+offset]
ham[: upper_fn(x) : step_fn(x)], ham[:: step_fn(x)]
ham[lower + offset : upper + offset]
slice[::, ::]
slice[
# A
:
# B
:
# C
]
slice[
# A
1:
# B
2:
# C
3
]
slice[
# A
1
+ 2 :
# B
3 :
# C
4
]
x[1:2:3] # A # B # C

View file

@ -0,0 +1,3 @@
def foo(
# type: Foo
x): pass

View file

@ -0,0 +1,5 @@
def foo(
# type: Foo
x,
):
pass

View file

@ -0,0 +1,113 @@
#!/usr/bin/python3
from __future__ import annotations
import argparse
from pathlib import Path
def import_fixture(fixture: Path, fixture_set: str):
"""
Imports a single fixture by writing the input and expected output to the black directory.
"""
output_directory = Path(__file__).parent.joinpath("black").joinpath(fixture_set)
output_directory.mkdir(parents=True, exist_ok=True)
fixture_path = output_directory.joinpath(fixture.name)
expect_path = fixture_path.with_suffix(".py.expect")
with (
fixture.open("r") as black_file,
fixture_path.open("w") as fixture_file,
expect_path.open("w") as expect_file
):
lines = iter(black_file)
expected = []
input = []
for line in lines:
if line.rstrip() == "# output":
expected = list(lines)
break
else:
input.append(line)
if not expected:
# If there's no output marker, tread the whole file as already pre-formatted
expected = input
fixture_file.write("".join(input).strip() + "\n")
expect_file.write("".join(expected).strip() + "\n")
# The name of the folders in the `data` for which the tests should be imported
FIXTURE_SETS = [
"py_36",
"py_37",
"py_38",
"py_39",
"py_310",
"py_311",
"simple_cases",
"miscellaneous",
".",
"type_comments"
]
# Tests that ruff doesn't fully support yet and, therefore, should not be imported
IGNORE_LIST = [
"pep_572_remove_parens.py", # Reformatting bugs
"pep_646.py", # Rust Python parser bug
# Contain syntax errors
"async_as_identifier.py",
"invalid_header.py",
"pattern_matching_invalid.py",
# Python 2
"python2_detection.py"
]
def import_fixtures(black_dir: str):
"""Imports all the black fixtures"""
test_directory = Path(black_dir, "tests/data")
if not test_directory.exists():
print(
"Black directory does not contain a 'tests/data' directory. Does the directory point to a full black "
"checkout (git clone https://github.com/psf/black.git)?")
return
for fixture_set in FIXTURE_SETS:
fixture_directory = test_directory.joinpath(fixture_set)
fixtures = fixture_directory.glob("*.py")
if not fixtures:
print(f"Fixture set '{fixture_set}' contains no python files")
return
for fixture in fixtures:
if fixture.name in IGNORE_LIST:
print(f"Ignoring fixture '{fixture}")
continue
print(f"Importing fixture '{fixture}")
import_fixture(fixture, fixture_set)
if __name__ == '__main__':
parser = argparse.ArgumentParser(
description="Imports the test suite from black.",
epilog="import_black_tests.py <path_to_black_repository>"
)
parser.add_argument("black_dir", type=Path)
args = parser.parse_args()
black_dir = args.black_dir
import_fixtures(black_dir)

View file

@ -12,7 +12,12 @@ fn black_compatibility() {
let content = fs::read_to_string(input_path).unwrap();
let options = PyFormatOptions::default();
let printed = format_module(&content, options.clone()).expect("Formatting to succeed");
let printed = format_module(&content, options.clone()).unwrap_or_else(|err| {
panic!(
"Formatting of {} to succeed but encountered error {err}",
input_path.display()
)
});
let expected_path = input_path.with_extension("py.expect");
let expected_output = fs::read_to_string(&expected_path)
@ -20,7 +25,7 @@ fn black_compatibility() {
let formatted_code = printed.as_code();
ensure_stability_when_formatting_twice(formatted_code, options);
ensure_stability_when_formatting_twice(formatted_code, options, input_path);
if formatted_code == expected_output {
// Black and Ruff formatting matches. Delete any existing snapshot files because the Black output
@ -95,7 +100,7 @@ fn format() {
let printed = format_module(&content, options.clone()).expect("Formatting to succeed");
let formatted_code = printed.as_code();
ensure_stability_when_formatting_twice(formatted_code, options);
ensure_stability_when_formatting_twice(formatted_code, options, input_path);
let mut snapshot = format!("## Input\n{}", CodeFrame::new("py", &content));
@ -112,7 +117,7 @@ fn format() {
format_module(&content, options.clone()).expect("Formatting to succeed");
let formatted_code = printed.as_code();
ensure_stability_when_formatting_twice(formatted_code, options.clone());
ensure_stability_when_formatting_twice(formatted_code, options.clone(), input_path);
writeln!(
snapshot,
@ -128,7 +133,7 @@ fn format() {
let printed = format_module(&content, options.clone()).expect("Formatting to succeed");
let formatted_code = printed.as_code();
ensure_stability_when_formatting_twice(formatted_code, options);
ensure_stability_when_formatting_twice(formatted_code, options, input_path);
writeln!(
snapshot,
@ -151,13 +156,18 @@ fn format() {
}
/// Format another time and make sure that there are no changes anymore
fn ensure_stability_when_formatting_twice(formatted_code: &str, options: PyFormatOptions) {
fn ensure_stability_when_formatting_twice(
formatted_code: &str,
options: PyFormatOptions,
input_path: &Path,
) {
let reformatted = match format_module(formatted_code, options) {
Ok(reformatted) => reformatted,
Err(err) => {
panic!(
"Expected formatted code to be valid syntax: {err}:\
"Expected formatted code of {} to be valid syntax: {err}:\
\n---\n{formatted_code}---\n",
input_path.display()
);
}
};
@ -168,7 +178,7 @@ fn ensure_stability_when_formatting_twice(formatted_code: &str, options: PyForma
.header("Formatted once", "Formatted twice")
.to_string();
panic!(
r#"Reformatting the formatted code a second time resulted in formatting changes.
r#"Reformatting the formatted code of {} a second time resulted in formatting changes.
---
{diff}---
@ -179,7 +189,8 @@ Formatted once:
Formatted twice:
---
{}---"#,
reformatted.as_code()
input_path.display(),
reformatted.as_code(),
);
}
}

View file

@ -0,0 +1,334 @@
---
source: crates/ruff_python_formatter/tests/fixtures.rs
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/conditional_expression.py
---
## Input
```py
long_kwargs_single_line = my_function(
foo="test, this is a sample value",
bar=some_long_value_name_foo_bar_baz if some_boolean_variable else some_fallback_value_foo_bar_baz,
baz="hello, this is a another value",
)
multiline_kwargs_indented = my_function(
foo="test, this is a sample value",
bar=some_long_value_name_foo_bar_baz
if some_boolean_variable
else some_fallback_value_foo_bar_baz,
baz="hello, this is a another value",
)
imploding_kwargs = my_function(
foo="test, this is a sample value",
bar=a
if foo
else b,
baz="hello, this is a another value",
)
imploding_line = (
1
if 1 + 1 == 2
else 0
)
exploding_line = "hello this is a slightly long string" if some_long_value_name_foo_bar_baz else "this one is a little shorter"
positional_argument_test(some_long_value_name_foo_bar_baz if some_boolean_variable else some_fallback_value_foo_bar_baz)
def weird_default_argument(x=some_long_value_name_foo_bar_baz
if SOME_CONSTANT
else some_fallback_value_foo_bar_baz):
pass
nested = "hello this is a slightly long string" if (some_long_value_name_foo_bar_baz if
nesting_test_expressions else some_fallback_value_foo_bar_baz) \
else "this one is a little shorter"
generator_expression = (
some_long_value_name_foo_bar_baz if some_boolean_variable else some_fallback_value_foo_bar_baz for some_boolean_variable in some_iterable
)
def limit_offset_sql(self, low_mark, high_mark):
"""Return LIMIT/OFFSET SQL clause."""
limit, offset = self._get_limit_offset_params(low_mark, high_mark)
return " ".join(
sql
for sql in (
"LIMIT %d" % limit if limit else None,
("OFFSET %d" % offset) if offset else None,
)
if sql
)
def something():
clone._iterable_class = (
NamedValuesListIterable
if named
else FlatValuesListIterable
if flat
else ValuesListIterable
)
```
## Black Differences
```diff
--- Black
+++ Ruff
@@ -1,90 +1,48 @@
long_kwargs_single_line = my_function(
foo="test, this is a sample value",
- bar=(
- some_long_value_name_foo_bar_baz
- if some_boolean_variable
- else some_fallback_value_foo_bar_baz
- ),
+ bar=NOT_IMPLEMENTED_true if NOT_IMPLEMENTED_cond else NOT_IMPLEMENTED_false,
baz="hello, this is a another value",
)
multiline_kwargs_indented = my_function(
foo="test, this is a sample value",
- bar=(
- some_long_value_name_foo_bar_baz
- if some_boolean_variable
- else some_fallback_value_foo_bar_baz
- ),
+ bar=NOT_IMPLEMENTED_true if NOT_IMPLEMENTED_cond else NOT_IMPLEMENTED_false,
baz="hello, this is a another value",
)
imploding_kwargs = my_function(
foo="test, this is a sample value",
- bar=a if foo else b,
+ bar=NOT_IMPLEMENTED_true if NOT_IMPLEMENTED_cond else NOT_IMPLEMENTED_false,
baz="hello, this is a another value",
)
-imploding_line = 1 if 1 + 1 == 2 else 0
+imploding_line = NOT_IMPLEMENTED_true if NOT_IMPLEMENTED_cond else NOT_IMPLEMENTED_false
-exploding_line = (
- "hello this is a slightly long string"
- if some_long_value_name_foo_bar_baz
- else "this one is a little shorter"
-)
+exploding_line = NOT_IMPLEMENTED_true if NOT_IMPLEMENTED_cond else NOT_IMPLEMENTED_false
positional_argument_test(
- some_long_value_name_foo_bar_baz
- if some_boolean_variable
- else some_fallback_value_foo_bar_baz
+ NOT_IMPLEMENTED_true if NOT_IMPLEMENTED_cond else NOT_IMPLEMENTED_false
)
def weird_default_argument(
- x=(
- some_long_value_name_foo_bar_baz
- if SOME_CONSTANT
- else some_fallback_value_foo_bar_baz
- ),
+ x=NOT_IMPLEMENTED_true if NOT_IMPLEMENTED_cond else NOT_IMPLEMENTED_false
):
pass
-nested = (
- "hello this is a slightly long string"
- if (
- some_long_value_name_foo_bar_baz
- if nesting_test_expressions
- else some_fallback_value_foo_bar_baz
- )
- else "this one is a little shorter"
-)
+nested = NOT_IMPLEMENTED_true if NOT_IMPLEMENTED_cond else NOT_IMPLEMENTED_false
-generator_expression = (
- (
- some_long_value_name_foo_bar_baz
- if some_boolean_variable
- else some_fallback_value_foo_bar_baz
- )
- for some_boolean_variable in some_iterable
-)
+generator_expression = (i for i in [])
def limit_offset_sql(self, low_mark, high_mark):
"""Return LIMIT/OFFSET SQL clause."""
limit, offset = self._get_limit_offset_params(low_mark, high_mark)
- return " ".join(
- sql
- for sql in (
- "LIMIT %d" % limit if limit else None,
- ("OFFSET %d" % offset) if offset else None,
- )
- if sql
- )
+ return " ".join((i for i in []))
def something():
clone._iterable_class = (
- NamedValuesListIterable
- if named
- else FlatValuesListIterable if flat else ValuesListIterable
+ NOT_IMPLEMENTED_true if NOT_IMPLEMENTED_cond else NOT_IMPLEMENTED_false
)
```
## Ruff Output
```py
long_kwargs_single_line = my_function(
foo="test, this is a sample value",
bar=NOT_IMPLEMENTED_true if NOT_IMPLEMENTED_cond else NOT_IMPLEMENTED_false,
baz="hello, this is a another value",
)
multiline_kwargs_indented = my_function(
foo="test, this is a sample value",
bar=NOT_IMPLEMENTED_true if NOT_IMPLEMENTED_cond else NOT_IMPLEMENTED_false,
baz="hello, this is a another value",
)
imploding_kwargs = my_function(
foo="test, this is a sample value",
bar=NOT_IMPLEMENTED_true if NOT_IMPLEMENTED_cond else NOT_IMPLEMENTED_false,
baz="hello, this is a another value",
)
imploding_line = NOT_IMPLEMENTED_true if NOT_IMPLEMENTED_cond else NOT_IMPLEMENTED_false
exploding_line = NOT_IMPLEMENTED_true if NOT_IMPLEMENTED_cond else NOT_IMPLEMENTED_false
positional_argument_test(
NOT_IMPLEMENTED_true if NOT_IMPLEMENTED_cond else NOT_IMPLEMENTED_false
)
def weird_default_argument(
x=NOT_IMPLEMENTED_true if NOT_IMPLEMENTED_cond else NOT_IMPLEMENTED_false
):
pass
nested = NOT_IMPLEMENTED_true if NOT_IMPLEMENTED_cond else NOT_IMPLEMENTED_false
generator_expression = (i for i in [])
def limit_offset_sql(self, low_mark, high_mark):
"""Return LIMIT/OFFSET SQL clause."""
limit, offset = self._get_limit_offset_params(low_mark, high_mark)
return " ".join((i for i in []))
def something():
clone._iterable_class = (
NOT_IMPLEMENTED_true if NOT_IMPLEMENTED_cond else NOT_IMPLEMENTED_false
)
```
## Black Output
```py
long_kwargs_single_line = my_function(
foo="test, this is a sample value",
bar=(
some_long_value_name_foo_bar_baz
if some_boolean_variable
else some_fallback_value_foo_bar_baz
),
baz="hello, this is a another value",
)
multiline_kwargs_indented = my_function(
foo="test, this is a sample value",
bar=(
some_long_value_name_foo_bar_baz
if some_boolean_variable
else some_fallback_value_foo_bar_baz
),
baz="hello, this is a another value",
)
imploding_kwargs = my_function(
foo="test, this is a sample value",
bar=a if foo else b,
baz="hello, this is a another value",
)
imploding_line = 1 if 1 + 1 == 2 else 0
exploding_line = (
"hello this is a slightly long string"
if some_long_value_name_foo_bar_baz
else "this one is a little shorter"
)
positional_argument_test(
some_long_value_name_foo_bar_baz
if some_boolean_variable
else some_fallback_value_foo_bar_baz
)
def weird_default_argument(
x=(
some_long_value_name_foo_bar_baz
if SOME_CONSTANT
else some_fallback_value_foo_bar_baz
),
):
pass
nested = (
"hello this is a slightly long string"
if (
some_long_value_name_foo_bar_baz
if nesting_test_expressions
else some_fallback_value_foo_bar_baz
)
else "this one is a little shorter"
)
generator_expression = (
(
some_long_value_name_foo_bar_baz
if some_boolean_variable
else some_fallback_value_foo_bar_baz
)
for some_boolean_variable in some_iterable
)
def limit_offset_sql(self, low_mark, high_mark):
"""Return LIMIT/OFFSET SQL clause."""
limit, offset = self._get_limit_offset_params(low_mark, high_mark)
return " ".join(
sql
for sql in (
"LIMIT %d" % limit if limit else None,
("OFFSET %d" % offset) if offset else None,
)
if sql
)
def something():
clone._iterable_class = (
NamedValuesListIterable
if named
else FlatValuesListIterable if flat else ValuesListIterable
)
```

View file

@ -0,0 +1,55 @@
---
source: crates/ruff_python_formatter/tests/fixtures.rs
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/miscellaneous/blackd_diff.py
---
## Input
```py
def abc ():
return ["hello", "world",
"!"]
print( "Incorrect formatting"
)
```
## Black Differences
```diff
--- Black
+++ Ruff
@@ -1,6 +1,5 @@
-def abc ():
- return ["hello", "world",
- "!"]
+def abc():
+ return ["hello", "world", "!"]
-print( "Incorrect formatting"
-)
+
+print("Incorrect formatting")
```
## Ruff Output
```py
def abc():
return ["hello", "world", "!"]
print("Incorrect formatting")
```
## Black Output
```py
def abc ():
return ["hello", "world",
"!"]
print( "Incorrect formatting"
)
```

View file

@ -0,0 +1,167 @@
---
source: crates/ruff_python_formatter/tests/fixtures.rs
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/miscellaneous/debug_visitor.py
---
## Input
```py
@dataclass
class DebugVisitor(Visitor[T]):
tree_depth: int = 0
def visit_default(self, node: LN) -> Iterator[T]:
indent = ' ' * (2 * self.tree_depth)
if isinstance(node, Node):
_type = type_repr(node.type)
out(f'{indent}{_type}', fg='yellow')
self.tree_depth += 1
for child in node.children:
yield from self.visit(child)
self.tree_depth -= 1
out(f'{indent}/{_type}', fg='yellow', bold=False)
else:
_type = token.tok_name.get(node.type, str(node.type))
out(f'{indent}{_type}', fg='blue', nl=False)
if node.prefix:
# We don't have to handle prefixes for `Node` objects since
# that delegates to the first child anyway.
out(f' {node.prefix!r}', fg='green', bold=False, nl=False)
out(f' {node.value!r}', fg='blue', bold=False)
@classmethod
def show(cls, code: str) -> None:
"""Pretty-prints a given string of `code`.
Convenience method for debugging.
"""
v: DebugVisitor[None] = DebugVisitor()
list(v.visit(lib2to3_parse(code)))
```
## Black Differences
```diff
--- Black
+++ Ruff
@@ -1,26 +1,26 @@
@dataclass
class DebugVisitor(Visitor[T]):
- tree_depth: int = 0
+ NOT_YET_IMPLEMENTED_StmtAnnAssign
def visit_default(self, node: LN) -> Iterator[T]:
- indent = ' ' * (2 * self.tree_depth)
+ indent = " " * (2 * self.tree_depth)
if isinstance(node, Node):
_type = type_repr(node.type)
- out(f'{indent}{_type}', fg='yellow')
- self.tree_depth += 1
+ out(NOT_YET_IMPLEMENTED_ExprJoinedStr, fg="yellow")
+ NOT_YET_IMPLEMENTED_StmtAugAssign
for child in node.children:
- yield from self.visit(child)
+ NOT_YET_IMPLEMENTED_ExprYieldFrom
- self.tree_depth -= 1
- out(f'{indent}/{_type}', fg='yellow', bold=False)
+ NOT_YET_IMPLEMENTED_StmtAugAssign
+ out(NOT_YET_IMPLEMENTED_ExprJoinedStr, fg="yellow", bold=False)
else:
_type = token.tok_name.get(node.type, str(node.type))
- out(f'{indent}{_type}', fg='blue', nl=False)
+ out(NOT_YET_IMPLEMENTED_ExprJoinedStr, fg="blue", nl=False)
if node.prefix:
# We don't have to handle prefixes for `Node` objects since
# that delegates to the first child anyway.
- out(f' {node.prefix!r}', fg='green', bold=False, nl=False)
- out(f' {node.value!r}', fg='blue', bold=False)
+ out(NOT_YET_IMPLEMENTED_ExprJoinedStr, fg="green", bold=False, nl=False)
+ out(NOT_YET_IMPLEMENTED_ExprJoinedStr, fg="blue", bold=False)
@classmethod
def show(cls, code: str) -> None:
@@ -28,5 +28,5 @@
Convenience method for debugging.
"""
- v: DebugVisitor[None] = DebugVisitor()
+ NOT_YET_IMPLEMENTED_StmtAnnAssign
list(v.visit(lib2to3_parse(code)))
```
## Ruff Output
```py
@dataclass
class DebugVisitor(Visitor[T]):
NOT_YET_IMPLEMENTED_StmtAnnAssign
def visit_default(self, node: LN) -> Iterator[T]:
indent = " " * (2 * self.tree_depth)
if isinstance(node, Node):
_type = type_repr(node.type)
out(NOT_YET_IMPLEMENTED_ExprJoinedStr, fg="yellow")
NOT_YET_IMPLEMENTED_StmtAugAssign
for child in node.children:
NOT_YET_IMPLEMENTED_ExprYieldFrom
NOT_YET_IMPLEMENTED_StmtAugAssign
out(NOT_YET_IMPLEMENTED_ExprJoinedStr, fg="yellow", bold=False)
else:
_type = token.tok_name.get(node.type, str(node.type))
out(NOT_YET_IMPLEMENTED_ExprJoinedStr, fg="blue", nl=False)
if node.prefix:
# We don't have to handle prefixes for `Node` objects since
# that delegates to the first child anyway.
out(NOT_YET_IMPLEMENTED_ExprJoinedStr, fg="green", bold=False, nl=False)
out(NOT_YET_IMPLEMENTED_ExprJoinedStr, fg="blue", bold=False)
@classmethod
def show(cls, code: str) -> None:
"""Pretty-prints a given string of `code`.
Convenience method for debugging.
"""
NOT_YET_IMPLEMENTED_StmtAnnAssign
list(v.visit(lib2to3_parse(code)))
```
## Black Output
```py
@dataclass
class DebugVisitor(Visitor[T]):
tree_depth: int = 0
def visit_default(self, node: LN) -> Iterator[T]:
indent = ' ' * (2 * self.tree_depth)
if isinstance(node, Node):
_type = type_repr(node.type)
out(f'{indent}{_type}', fg='yellow')
self.tree_depth += 1
for child in node.children:
yield from self.visit(child)
self.tree_depth -= 1
out(f'{indent}/{_type}', fg='yellow', bold=False)
else:
_type = token.tok_name.get(node.type, str(node.type))
out(f'{indent}{_type}', fg='blue', nl=False)
if node.prefix:
# We don't have to handle prefixes for `Node` objects since
# that delegates to the first child anyway.
out(f' {node.prefix!r}', fg='green', bold=False, nl=False)
out(f' {node.value!r}', fg='blue', bold=False)
@classmethod
def show(cls, code: str) -> None:
"""Pretty-prints a given string of `code`.
Convenience method for debugging.
"""
v: DebugVisitor[None] = DebugVisitor()
list(v.visit(lib2to3_parse(code)))
```

View file

@ -0,0 +1,576 @@
---
source: crates/ruff_python_formatter/tests/fixtures.rs
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/miscellaneous/decorators.py
---
## Input
```py
# This file doesn't use the standard decomposition.
# Decorator syntax test cases are separated by double # comments.
# Those before the 'output' comment are valid under the old syntax.
# Those after the 'ouput' comment require PEP614 relaxed syntax.
# Do not remove the double # separator before the first test case, it allows
# the comment before the test case to be ignored.
##
@decorator
def f():
...
##
@decorator()
def f():
...
##
@decorator(arg)
def f():
...
##
@decorator(kwarg=0)
def f():
...
##
@decorator(*args)
def f():
...
##
@decorator(**kwargs)
def f():
...
##
@decorator(*args, **kwargs)
def f():
...
##
@decorator(*args, **kwargs,)
def f():
...
##
@dotted.decorator
def f():
...
##
@dotted.decorator(arg)
def f():
...
##
@dotted.decorator(kwarg=0)
def f():
...
##
@dotted.decorator(*args)
def f():
...
##
@dotted.decorator(**kwargs)
def f():
...
##
@dotted.decorator(*args, **kwargs)
def f():
...
##
@dotted.decorator(*args, **kwargs,)
def f():
...
##
@double.dotted.decorator
def f():
...
##
@double.dotted.decorator(arg)
def f():
...
##
@double.dotted.decorator(kwarg=0)
def f():
...
##
@double.dotted.decorator(*args)
def f():
...
##
@double.dotted.decorator(**kwargs)
def f():
...
##
@double.dotted.decorator(*args, **kwargs)
def f():
...
##
@double.dotted.decorator(*args, **kwargs,)
def f():
...
##
@_(sequence["decorator"])
def f():
...
##
@eval("sequence['decorator']")
def f():
...
```
## Black Differences
```diff
--- Black
+++ Ruff
@@ -1,29 +1,182 @@
+# This file doesn't use the standard decomposition.
+# Decorator syntax test cases are separated by double # comments.
+# Those before the 'output' comment are valid under the old syntax.
+# Those after the 'ouput' comment require PEP614 relaxed syntax.
+# Do not remove the double # separator before the first test case, it allows
+# the comment before the test case to be ignored.
+
+##
+
+@decorator
+def f():
+ ...
+
+
+##
+
+@decorator()
+def f():
+ ...
+
+
+##
+
+@decorator(arg)
+def f():
+ ...
+
+
+##
+
+@decorator(kwarg=0)
+def f():
+ ...
+
+
+##
+
+@decorator(*NOT_YET_IMPLEMENTED_ExprStarred)
+def f():
+ ...
+
+
##
-@decorator()()
+@decorator(**kwargs)
def f():
...
+
##
-@(decorator)
+@decorator(*NOT_YET_IMPLEMENTED_ExprStarred, **kwargs)
def f():
...
+
##
-@sequence["decorator"]
+@decorator(
+ *NOT_YET_IMPLEMENTED_ExprStarred,
+ **kwargs,
+)
def f():
...
+
##
-@decorator[List[str]]
+@dotted.decorator
def f():
...
+
##
-@var := decorator
+@dotted.decorator(arg)
+def f():
+ ...
+
+
+##
+
+@dotted.decorator(kwarg=0)
+def f():
+ ...
+
+
+##
+
+@dotted.decorator(*NOT_YET_IMPLEMENTED_ExprStarred)
+def f():
+ ...
+
+
+##
+
+@dotted.decorator(**kwargs)
+def f():
+ ...
+
+
+##
+
+@dotted.decorator(*NOT_YET_IMPLEMENTED_ExprStarred, **kwargs)
+def f():
+ ...
+
+
+##
+
+@dotted.decorator(
+ *NOT_YET_IMPLEMENTED_ExprStarred,
+ **kwargs,
+)
+def f():
+ ...
+
+
+##
+
+@double.dotted.decorator
+def f():
+ ...
+
+
+##
+
+@double.dotted.decorator(arg)
+def f():
+ ...
+
+
+##
+
+@double.dotted.decorator(kwarg=0)
+def f():
+ ...
+
+
+##
+
+@double.dotted.decorator(*NOT_YET_IMPLEMENTED_ExprStarred)
+def f():
+ ...
+
+
+##
+
+@double.dotted.decorator(**kwargs)
+def f():
+ ...
+
+
+##
+
+@double.dotted.decorator(*NOT_YET_IMPLEMENTED_ExprStarred, **kwargs)
+def f():
+ ...
+
+
+##
+
+@double.dotted.decorator(
+ *NOT_YET_IMPLEMENTED_ExprStarred,
+ **kwargs,
+)
+def f():
+ ...
+
+
+##
+
+@_(sequence["decorator"])
+def f():
+ ...
+
+
+##
+
+@eval("sequence['decorator']")
def f():
...
```
## Ruff Output
```py
# This file doesn't use the standard decomposition.
# Decorator syntax test cases are separated by double # comments.
# Those before the 'output' comment are valid under the old syntax.
# Those after the 'ouput' comment require PEP614 relaxed syntax.
# Do not remove the double # separator before the first test case, it allows
# the comment before the test case to be ignored.
##
@decorator
def f():
...
##
@decorator()
def f():
...
##
@decorator(arg)
def f():
...
##
@decorator(kwarg=0)
def f():
...
##
@decorator(*NOT_YET_IMPLEMENTED_ExprStarred)
def f():
...
##
@decorator(**kwargs)
def f():
...
##
@decorator(*NOT_YET_IMPLEMENTED_ExprStarred, **kwargs)
def f():
...
##
@decorator(
*NOT_YET_IMPLEMENTED_ExprStarred,
**kwargs,
)
def f():
...
##
@dotted.decorator
def f():
...
##
@dotted.decorator(arg)
def f():
...
##
@dotted.decorator(kwarg=0)
def f():
...
##
@dotted.decorator(*NOT_YET_IMPLEMENTED_ExprStarred)
def f():
...
##
@dotted.decorator(**kwargs)
def f():
...
##
@dotted.decorator(*NOT_YET_IMPLEMENTED_ExprStarred, **kwargs)
def f():
...
##
@dotted.decorator(
*NOT_YET_IMPLEMENTED_ExprStarred,
**kwargs,
)
def f():
...
##
@double.dotted.decorator
def f():
...
##
@double.dotted.decorator(arg)
def f():
...
##
@double.dotted.decorator(kwarg=0)
def f():
...
##
@double.dotted.decorator(*NOT_YET_IMPLEMENTED_ExprStarred)
def f():
...
##
@double.dotted.decorator(**kwargs)
def f():
...
##
@double.dotted.decorator(*NOT_YET_IMPLEMENTED_ExprStarred, **kwargs)
def f():
...
##
@double.dotted.decorator(
*NOT_YET_IMPLEMENTED_ExprStarred,
**kwargs,
)
def f():
...
##
@_(sequence["decorator"])
def f():
...
##
@eval("sequence['decorator']")
def f():
...
```
## Black Output
```py
##
@decorator()()
def f():
...
##
@(decorator)
def f():
...
##
@sequence["decorator"]
def f():
...
##
@decorator[List[str]]
def f():
...
##
@var := decorator
def f():
...
```

View file

@ -0,0 +1,556 @@
---
source: crates/ruff_python_formatter/tests/fixtures.rs
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/miscellaneous/docstring_no_string_normalization.py
---
## Input
```py
class ALonelyClass:
'''
A multiline class docstring.
'''
def AnEquallyLonelyMethod(self):
'''
A multiline method docstring'''
pass
def one_function():
'''This is a docstring with a single line of text.'''
pass
def shockingly_the_quotes_are_normalized():
'''This is a multiline docstring.
This is a multiline docstring.
This is a multiline docstring.
'''
pass
def foo():
"""This is a docstring with
some lines of text here
"""
return
def baz():
'''"This" is a string with some
embedded "quotes"'''
return
def poit():
"""
Lorem ipsum dolor sit amet.
Consectetur adipiscing elit:
- sed do eiusmod tempor incididunt ut labore
- dolore magna aliqua
- enim ad minim veniam
- quis nostrud exercitation ullamco laboris nisi
- aliquip ex ea commodo consequat
"""
pass
def under_indent():
"""
These lines are indented in a way that does not
make sense.
"""
pass
def over_indent():
"""
This has a shallow indent
- But some lines are deeper
- And the closing quote is too deep
"""
pass
def single_line():
"""But with a newline after it!
"""
pass
def this():
r"""
'hey ho'
"""
def that():
""" "hey yah" """
def and_that():
"""
"hey yah" """
def and_this():
'''
"hey yah"'''
def believe_it_or_not_this_is_in_the_py_stdlib(): '''
"hey yah"'''
def shockingly_the_quotes_are_normalized_v2():
'''
Docstring Docstring Docstring
'''
pass
def backslash_space():
'\ '
def multiline_backslash_1():
'''
hey\there\
\ '''
def multiline_backslash_2():
'''
hey there \ '''
def multiline_backslash_3():
'''
already escaped \\ '''
```
## Black Differences
```diff
--- Black
+++ Ruff
@@ -1,73 +1,75 @@
class ALonelyClass:
- '''
+ """
A multiline class docstring.
- '''
+ """
def AnEquallyLonelyMethod(self):
- '''
- A multiline method docstring'''
+ """
+ A multiline method docstring"""
pass
def one_function():
- '''This is a docstring with a single line of text.'''
+ """This is a docstring with a single line of text."""
pass
def shockingly_the_quotes_are_normalized():
- '''This is a multiline docstring.
+ """This is a multiline docstring.
This is a multiline docstring.
This is a multiline docstring.
- '''
+ """
pass
def foo():
- """This is a docstring with
- some lines of text here
- """
+ """This is a docstring with
+ some lines of text here
+ """
return
def baz():
'''"This" is a string with some
- embedded "quotes"'''
+ embedded "quotes"'''
return
def poit():
"""
- Lorem ipsum dolor sit amet.
+ Lorem ipsum dolor sit amet.
- Consectetur adipiscing elit:
- - sed do eiusmod tempor incididunt ut labore
- - dolore magna aliqua
- - enim ad minim veniam
- - quis nostrud exercitation ullamco laboris nisi
- - aliquip ex ea commodo consequat
- """
+ Consectetur adipiscing elit:
+ - sed do eiusmod tempor incididunt ut labore
+ - dolore magna aliqua
+ - enim ad minim veniam
+ - quis nostrud exercitation ullamco laboris nisi
+ - aliquip ex ea commodo consequat
+ """
pass
def under_indent():
"""
- These lines are indented in a way that does not
- make sense.
- """
+ These lines are indented in a way that does not
+make sense.
+ """
pass
def over_indent():
"""
- This has a shallow indent
- - But some lines are deeper
- - And the closing quote is too deep
+ This has a shallow indent
+ - But some lines are deeper
+ - And the closing quote is too deep
"""
pass
def single_line():
- """But with a newline after it!"""
+ """But with a newline after it!
+
+ """
pass
@@ -83,41 +85,41 @@
def and_that():
"""
- "hey yah" """
+ "hey yah" """
def and_this():
- '''
- "hey yah"'''
+ '''
+ "hey yah"'''
def believe_it_or_not_this_is_in_the_py_stdlib():
- '''
- "hey yah"'''
+ '''
+"hey yah"'''
def shockingly_the_quotes_are_normalized_v2():
- '''
+ """
Docstring Docstring Docstring
- '''
+ """
pass
def backslash_space():
- '\ '
+ "\ "
def multiline_backslash_1():
- '''
+ """
hey\there\
- \ '''
+ \ """
def multiline_backslash_2():
- '''
- hey there \ '''
+ """
+ hey there \ """
def multiline_backslash_3():
- '''
- already escaped \\'''
+ """
+ already escaped \\ """
```
## Ruff Output
```py
class ALonelyClass:
"""
A multiline class docstring.
"""
def AnEquallyLonelyMethod(self):
"""
A multiline method docstring"""
pass
def one_function():
"""This is a docstring with a single line of text."""
pass
def shockingly_the_quotes_are_normalized():
"""This is a multiline docstring.
This is a multiline docstring.
This is a multiline docstring.
"""
pass
def foo():
"""This is a docstring with
some lines of text here
"""
return
def baz():
'''"This" is a string with some
embedded "quotes"'''
return
def poit():
"""
Lorem ipsum dolor sit amet.
Consectetur adipiscing elit:
- sed do eiusmod tempor incididunt ut labore
- dolore magna aliqua
- enim ad minim veniam
- quis nostrud exercitation ullamco laboris nisi
- aliquip ex ea commodo consequat
"""
pass
def under_indent():
"""
These lines are indented in a way that does not
make sense.
"""
pass
def over_indent():
"""
This has a shallow indent
- But some lines are deeper
- And the closing quote is too deep
"""
pass
def single_line():
"""But with a newline after it!
"""
pass
def this():
r"""
'hey ho'
"""
def that():
""" "hey yah" """
def and_that():
"""
"hey yah" """
def and_this():
'''
"hey yah"'''
def believe_it_or_not_this_is_in_the_py_stdlib():
'''
"hey yah"'''
def shockingly_the_quotes_are_normalized_v2():
"""
Docstring Docstring Docstring
"""
pass
def backslash_space():
"\ "
def multiline_backslash_1():
"""
hey\there\
\ """
def multiline_backslash_2():
"""
hey there \ """
def multiline_backslash_3():
"""
already escaped \\ """
```
## Black Output
```py
class ALonelyClass:
'''
A multiline class docstring.
'''
def AnEquallyLonelyMethod(self):
'''
A multiline method docstring'''
pass
def one_function():
'''This is a docstring with a single line of text.'''
pass
def shockingly_the_quotes_are_normalized():
'''This is a multiline docstring.
This is a multiline docstring.
This is a multiline docstring.
'''
pass
def foo():
"""This is a docstring with
some lines of text here
"""
return
def baz():
'''"This" is a string with some
embedded "quotes"'''
return
def poit():
"""
Lorem ipsum dolor sit amet.
Consectetur adipiscing elit:
- sed do eiusmod tempor incididunt ut labore
- dolore magna aliqua
- enim ad minim veniam
- quis nostrud exercitation ullamco laboris nisi
- aliquip ex ea commodo consequat
"""
pass
def under_indent():
"""
These lines are indented in a way that does not
make sense.
"""
pass
def over_indent():
"""
This has a shallow indent
- But some lines are deeper
- And the closing quote is too deep
"""
pass
def single_line():
"""But with a newline after it!"""
pass
def this():
r"""
'hey ho'
"""
def that():
""" "hey yah" """
def and_that():
"""
"hey yah" """
def and_this():
'''
"hey yah"'''
def believe_it_or_not_this_is_in_the_py_stdlib():
'''
"hey yah"'''
def shockingly_the_quotes_are_normalized_v2():
'''
Docstring Docstring Docstring
'''
pass
def backslash_space():
'\ '
def multiline_backslash_1():
'''
hey\there\
\ '''
def multiline_backslash_2():
'''
hey there \ '''
def multiline_backslash_3():
'''
already escaped \\'''
```

View file

@ -0,0 +1,68 @@
---
source: crates/ruff_python_formatter/tests/fixtures.rs
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/miscellaneous/docstring_preview_no_string_normalization.py
---
## Input
```py
def do_not_touch_this_prefix():
R"""There was a bug where docstring prefixes would be normalized even with -S."""
def do_not_touch_this_prefix2():
FR'There was a bug where docstring prefixes would be normalized even with -S.'
def do_not_touch_this_prefix3():
u'''There was a bug where docstring prefixes would be normalized even with -S.'''
```
## Black Differences
```diff
--- Black
+++ Ruff
@@ -3,8 +3,8 @@
def do_not_touch_this_prefix2():
- FR'There was a bug where docstring prefixes would be normalized even with -S.'
+ NOT_YET_IMPLEMENTED_ExprJoinedStr
def do_not_touch_this_prefix3():
- u'''There was a bug where docstring prefixes would be normalized even with -S.'''
+ """There was a bug where docstring prefixes would be normalized even with -S."""
```
## Ruff Output
```py
def do_not_touch_this_prefix():
R"""There was a bug where docstring prefixes would be normalized even with -S."""
def do_not_touch_this_prefix2():
NOT_YET_IMPLEMENTED_ExprJoinedStr
def do_not_touch_this_prefix3():
"""There was a bug where docstring prefixes would be normalized even with -S."""
```
## Black Output
```py
def do_not_touch_this_prefix():
R"""There was a bug where docstring prefixes would be normalized even with -S."""
def do_not_touch_this_prefix2():
FR'There was a bug where docstring prefixes would be normalized even with -S.'
def do_not_touch_this_prefix3():
u'''There was a bug where docstring prefixes would be normalized even with -S.'''
```

View file

@ -0,0 +1,220 @@
---
source: crates/ruff_python_formatter/tests/fixtures.rs
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/miscellaneous/force_pyi.py
---
## Input
```py
from typing import Union
@bird
def zoo(): ...
class A: ...
@bar
class B:
def BMethod(self) -> None: ...
@overload
def BMethod(self, arg : List[str]) -> None: ...
class C: ...
@hmm
class D: ...
class E: ...
@baz
def foo() -> None:
...
class F (A , C): ...
def spam() -> None: ...
@overload
def spam(arg: str) -> str: ...
var : int = 1
def eggs() -> Union[str, int]: ...
```
## Black Differences
```diff
--- Black
+++ Ruff
@@ -1,32 +1,58 @@
-from typing import Union
+NOT_YET_IMPLEMENTED_StmtImportFrom
+
@bird
-def zoo(): ...
+def zoo():
+ ...
+
+
+class A:
+ ...
-class A: ...
@bar
class B:
- def BMethod(self) -> None: ...
+ def BMethod(self) -> None:
+ ...
+
@overload
- def BMethod(self, arg: List[str]) -> None: ...
+ def BMethod(self, arg: List[str]) -> None:
+ ...
-class C: ...
+class C:
+ ...
+
+
@hmm
-class D: ...
+class D:
+ ...
+
+
+class E:
+ ...
-class E: ...
@baz
-def foo() -> None: ...
+def foo() -> None:
+ ...
+
+
+class F(A, C):
+ ...
-class F(A, C): ...
-def spam() -> None: ...
+def spam() -> None:
+ ...
+
+
@overload
-def spam(arg: str) -> str: ...
+def spam(arg: str) -> str:
+ ...
+
+
+NOT_YET_IMPLEMENTED_StmtAnnAssign
-var: int = 1
-def eggs() -> Union[str, int]: ...
+def eggs() -> Union[str, int]:
+ ...
```
## Ruff Output
```py
NOT_YET_IMPLEMENTED_StmtImportFrom
@bird
def zoo():
...
class A:
...
@bar
class B:
def BMethod(self) -> None:
...
@overload
def BMethod(self, arg: List[str]) -> None:
...
class C:
...
@hmm
class D:
...
class E:
...
@baz
def foo() -> None:
...
class F(A, C):
...
def spam() -> None:
...
@overload
def spam(arg: str) -> str:
...
NOT_YET_IMPLEMENTED_StmtAnnAssign
def eggs() -> Union[str, int]:
...
```
## Black Output
```py
from typing import Union
@bird
def zoo(): ...
class A: ...
@bar
class B:
def BMethod(self) -> None: ...
@overload
def BMethod(self, arg: List[str]) -> None: ...
class C: ...
@hmm
class D: ...
class E: ...
@baz
def foo() -> None: ...
class F(A, C): ...
def spam() -> None: ...
@overload
def spam(arg: str) -> str: ...
var: int = 1
def eggs() -> Union[str, int]: ...
```

View file

@ -0,0 +1,44 @@
---
source: crates/ruff_python_formatter/tests/fixtures.rs
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/miscellaneous/power_op_newline.py
---
## Input
```py
importA;()<<0**0#
```
## Black Differences
```diff
--- Black
+++ Ruff
@@ -1,6 +1,2 @@
importA
-(
- ()
- << 0
- ** 0
-) #
+() << 0**0 #
```
## Ruff Output
```py
importA
() << 0**0 #
```
## Black Output
```py
importA
(
()
<< 0
** 0
) #
```

View file

@ -0,0 +1,244 @@
---
source: crates/ruff_python_formatter/tests/fixtures.rs
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/miscellaneous/string_quotes.py
---
## Input
```py
''''''
'\''
'"'
"'"
"\""
"Hello"
"Don't do that"
'Here is a "'
'What\'s the deal here?'
"What's the deal \"here\"?"
"And \"here\"?"
"""Strings with "" in them"""
'''Strings with "" in them'''
'''Here's a "'''
'''Here's a " '''
'''Just a normal triple
quote'''
f"just a normal {f} string"
f'''This is a triple-quoted {f}-string'''
f'MOAR {" ".join([])}'
f"MOAR {' '.join([])}"
r"raw string ftw"
r'Date d\'expiration:(.*)'
r'Tricky "quote'
r'Not-so-tricky \"quote'
rf'{yay}'
'\n\
The \"quick\"\n\
brown fox\n\
jumps over\n\
the \'lazy\' dog.\n\
'
re.compile(r'[\\"]')
"x = ''; y = \"\""
"x = '''; y = \"\""
"x = ''''; y = \"\""
"x = '' ''; y = \"\""
"x = ''; y = \"\"\""
"x = '''; y = \"\"\"\""
"x = ''''; y = \"\"\"\"\""
"x = '' ''; y = \"\"\"\"\""
'unnecessary \"\"escaping'
"unnecessary \'\'escaping"
'\\""'
"\\''"
'Lots of \\\\\\\\\'quotes\''
f'{y * " "} \'{z}\''
f'{{y * " "}} \'{z}\''
f'\'{z}\' {y * " "}'
f'{y * x} \'{z}\''
'\'{z}\' {y * " "}'
'{y * x} \'{z}\''
# We must bail out if changing the quotes would introduce backslashes in f-string
# expressions. xref: https://github.com/psf/black/issues/2348
f"\"{b}\"{' ' * (long-len(b)+1)}: \"{sts}\",\n"
f"\"{a}\"{'hello' * b}\"{c}\""
```
## Black Differences
```diff
--- Black
+++ Ruff
@@ -15,16 +15,21 @@
"""Here's a " """
"""Just a normal triple
quote"""
-f"just a normal {f} string"
-f"""This is a triple-quoted {f}-string"""
-f'MOAR {" ".join([])}'
-f"MOAR {' '.join([])}"
+NOT_YET_IMPLEMENTED_ExprJoinedStr
+NOT_YET_IMPLEMENTED_ExprJoinedStr
+NOT_YET_IMPLEMENTED_ExprJoinedStr
+NOT_YET_IMPLEMENTED_ExprJoinedStr
r"raw string ftw"
-r"Date d\'expiration:(.*)"
+r"Date d'expiration:(.*)"
r'Tricky "quote'
-r"Not-so-tricky \"quote"
-rf"{yay}"
-"\nThe \"quick\"\nbrown fox\njumps over\nthe 'lazy' dog.\n"
+r'Not-so-tricky "quote'
+NOT_YET_IMPLEMENTED_ExprJoinedStr
+"\n\
+The \"quick\"\n\
+brown fox\n\
+jumps over\n\
+the 'lazy' dog.\n\
+"
re.compile(r'[\\"]')
"x = ''; y = \"\""
"x = '''; y = \"\""
@@ -39,14 +44,14 @@
'\\""'
"\\''"
"Lots of \\\\\\\\'quotes'"
-f'{y * " "} \'{z}\''
-f"{{y * \" \"}} '{z}'"
-f'\'{z}\' {y * " "}'
-f"{y * x} '{z}'"
+NOT_YET_IMPLEMENTED_ExprJoinedStr
+NOT_YET_IMPLEMENTED_ExprJoinedStr
+NOT_YET_IMPLEMENTED_ExprJoinedStr
+NOT_YET_IMPLEMENTED_ExprJoinedStr
"'{z}' {y * \" \"}"
"{y * x} '{z}'"
# We must bail out if changing the quotes would introduce backslashes in f-string
# expressions. xref: https://github.com/psf/black/issues/2348
-f"\"{b}\"{' ' * (long-len(b)+1)}: \"{sts}\",\n"
-f"\"{a}\"{'hello' * b}\"{c}\""
+NOT_YET_IMPLEMENTED_ExprJoinedStr
+NOT_YET_IMPLEMENTED_ExprJoinedStr
```
## Ruff Output
```py
""""""
"'"
'"'
"'"
'"'
"Hello"
"Don't do that"
'Here is a "'
"What's the deal here?"
'What\'s the deal "here"?'
'And "here"?'
"""Strings with "" in them"""
"""Strings with "" in them"""
'''Here's a "'''
"""Here's a " """
"""Just a normal triple
quote"""
NOT_YET_IMPLEMENTED_ExprJoinedStr
NOT_YET_IMPLEMENTED_ExprJoinedStr
NOT_YET_IMPLEMENTED_ExprJoinedStr
NOT_YET_IMPLEMENTED_ExprJoinedStr
r"raw string ftw"
r"Date d'expiration:(.*)"
r'Tricky "quote'
r'Not-so-tricky "quote'
NOT_YET_IMPLEMENTED_ExprJoinedStr
"\n\
The \"quick\"\n\
brown fox\n\
jumps over\n\
the 'lazy' dog.\n\
"
re.compile(r'[\\"]')
"x = ''; y = \"\""
"x = '''; y = \"\""
"x = ''''; y = \"\""
"x = '' ''; y = \"\""
'x = \'\'; y = """'
'x = \'\'\'; y = """"'
'x = \'\'\'\'; y = """""'
'x = \'\' \'\'; y = """""'
'unnecessary ""escaping'
"unnecessary ''escaping"
'\\""'
"\\''"
"Lots of \\\\\\\\'quotes'"
NOT_YET_IMPLEMENTED_ExprJoinedStr
NOT_YET_IMPLEMENTED_ExprJoinedStr
NOT_YET_IMPLEMENTED_ExprJoinedStr
NOT_YET_IMPLEMENTED_ExprJoinedStr
"'{z}' {y * \" \"}"
"{y * x} '{z}'"
# We must bail out if changing the quotes would introduce backslashes in f-string
# expressions. xref: https://github.com/psf/black/issues/2348
NOT_YET_IMPLEMENTED_ExprJoinedStr
NOT_YET_IMPLEMENTED_ExprJoinedStr
```
## Black Output
```py
""""""
"'"
'"'
"'"
'"'
"Hello"
"Don't do that"
'Here is a "'
"What's the deal here?"
'What\'s the deal "here"?'
'And "here"?'
"""Strings with "" in them"""
"""Strings with "" in them"""
'''Here's a "'''
"""Here's a " """
"""Just a normal triple
quote"""
f"just a normal {f} string"
f"""This is a triple-quoted {f}-string"""
f'MOAR {" ".join([])}'
f"MOAR {' '.join([])}"
r"raw string ftw"
r"Date d\'expiration:(.*)"
r'Tricky "quote'
r"Not-so-tricky \"quote"
rf"{yay}"
"\nThe \"quick\"\nbrown fox\njumps over\nthe 'lazy' dog.\n"
re.compile(r'[\\"]')
"x = ''; y = \"\""
"x = '''; y = \"\""
"x = ''''; y = \"\""
"x = '' ''; y = \"\""
'x = \'\'; y = """'
'x = \'\'\'; y = """"'
'x = \'\'\'\'; y = """""'
'x = \'\' \'\'; y = """""'
'unnecessary ""escaping'
"unnecessary ''escaping"
'\\""'
"\\''"
"Lots of \\\\\\\\'quotes'"
f'{y * " "} \'{z}\''
f"{{y * \" \"}} '{z}'"
f'\'{z}\' {y * " "}'
f"{y * x} '{z}'"
"'{z}' {y * \" \"}"
"{y * x} '{z}'"
# We must bail out if changing the quotes would introduce backslashes in f-string
# expressions. xref: https://github.com/psf/black/issues/2348
f"\"{b}\"{' ' * (long-len(b)+1)}: \"{sts}\",\n"
f"\"{a}\"{'hello' * b}\"{c}\""
```

View file

@ -0,0 +1,549 @@
---
source: crates/ruff_python_formatter/tests/fixtures.rs
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/py_310/pattern_matching_complex.py
---
## Input
```py
# Cases sampled from Lib/test/test_patma.py
# case black_test_patma_098
match x:
case -0j:
y = 0
# case black_test_patma_142
match x:
case bytes(z):
y = 0
# case black_test_patma_073
match x:
case 0 if 0:
y = 0
case 0 if 1:
y = 1
# case black_test_patma_006
match 3:
case 0 | 1 | 2 | 3:
x = True
# case black_test_patma_049
match x:
case [0, 1] | [1, 0]:
y = 0
# case black_check_sequence_then_mapping
match x:
case [*_]:
return "seq"
case {}:
return "map"
# case black_test_patma_035
match x:
case {0: [1, 2, {}]}:
y = 0
case {0: [1, 2, {}] | True} | {1: [[]]} | {0: [1, 2, {}]} | [] | "X" | {}:
y = 1
case []:
y = 2
# case black_test_patma_107
match x:
case 0.25 + 1.75j:
y = 0
# case black_test_patma_097
match x:
case -0j:
y = 0
# case black_test_patma_007
match 4:
case 0 | 1 | 2 | 3:
x = True
# case black_test_patma_154
match x:
case 0 if x:
y = 0
# case black_test_patma_134
match x:
case {1: 0}:
y = 0
case {0: 0}:
y = 1
case {**z}:
y = 2
# case black_test_patma_185
match Seq():
case [*_]:
y = 0
# case black_test_patma_063
match x:
case 1:
y = 0
case 1:
y = 1
# case black_test_patma_248
match x:
case {"foo": bar}:
y = bar
# case black_test_patma_019
match (0, 1, 2):
case [0, 1, *x, 2]:
y = 0
# case black_test_patma_052
match x:
case [0]:
y = 0
case [1, 0] if (x := x[:0]):
y = 1
case [1, 0]:
y = 2
# case black_test_patma_191
match w:
case [x, y, *_]:
z = 0
# case black_test_patma_110
match x:
case -0.25 - 1.75j:
y = 0
# case black_test_patma_151
match (x,):
case [y]:
z = 0
# case black_test_patma_114
match x:
case A.B.C.D:
y = 0
# case black_test_patma_232
match x:
case None:
y = 0
# case black_test_patma_058
match x:
case 0:
y = 0
# case black_test_patma_233
match x:
case False:
y = 0
# case black_test_patma_078
match x:
case []:
y = 0
case [""]:
y = 1
case "":
y = 2
# case black_test_patma_156
match x:
case z:
y = 0
# case black_test_patma_189
match w:
case [x, y, *rest]:
z = 0
# case black_test_patma_042
match x:
case (0 as z) | (1 as z) | (2 as z) if z == x % 2:
y = 0
# case black_test_patma_034
match x:
case {0: [1, 2, {}]}:
y = 0
case {0: [1, 2, {}] | False} | {1: [[]]} | {0: [1, 2, {}]} | [] | "X" | {}:
y = 1
case []:
y = 2
```
## Black Differences
```diff
--- Black
+++ Ruff
@@ -1,144 +1,60 @@
# Cases sampled from Lib/test/test_patma.py
# case black_test_patma_098
-match x:
- case -0j:
- y = 0
+NOT_YET_IMPLEMENTED_StmtMatch
# case black_test_patma_142
-match x:
- case bytes(z):
- y = 0
+NOT_YET_IMPLEMENTED_StmtMatch
# case black_test_patma_073
-match x:
- case 0 if 0:
- y = 0
- case 0 if 1:
- y = 1
+NOT_YET_IMPLEMENTED_StmtMatch
# case black_test_patma_006
-match 3:
- case 0 | 1 | 2 | 3:
- x = True
+NOT_YET_IMPLEMENTED_StmtMatch
# case black_test_patma_049
-match x:
- case [0, 1] | [1, 0]:
- y = 0
+NOT_YET_IMPLEMENTED_StmtMatch
# case black_check_sequence_then_mapping
-match x:
- case [*_]:
- return "seq"
- case {}:
- return "map"
+NOT_YET_IMPLEMENTED_StmtMatch
# case black_test_patma_035
-match x:
- case {0: [1, 2, {}]}:
- y = 0
- case {0: [1, 2, {}] | True} | {1: [[]]} | {0: [1, 2, {}]} | [] | "X" | {}:
- y = 1
- case []:
- y = 2
+NOT_YET_IMPLEMENTED_StmtMatch
# case black_test_patma_107
-match x:
- case 0.25 + 1.75j:
- y = 0
+NOT_YET_IMPLEMENTED_StmtMatch
# case black_test_patma_097
-match x:
- case -0j:
- y = 0
+NOT_YET_IMPLEMENTED_StmtMatch
# case black_test_patma_007
-match 4:
- case 0 | 1 | 2 | 3:
- x = True
+NOT_YET_IMPLEMENTED_StmtMatch
# case black_test_patma_154
-match x:
- case 0 if x:
- y = 0
+NOT_YET_IMPLEMENTED_StmtMatch
# case black_test_patma_134
-match x:
- case {1: 0}:
- y = 0
- case {0: 0}:
- y = 1
- case {**z}:
- y = 2
+NOT_YET_IMPLEMENTED_StmtMatch
# case black_test_patma_185
-match Seq():
- case [*_]:
- y = 0
+NOT_YET_IMPLEMENTED_StmtMatch
# case black_test_patma_063
-match x:
- case 1:
- y = 0
- case 1:
- y = 1
+NOT_YET_IMPLEMENTED_StmtMatch
# case black_test_patma_248
-match x:
- case {"foo": bar}:
- y = bar
+NOT_YET_IMPLEMENTED_StmtMatch
# case black_test_patma_019
-match (0, 1, 2):
- case [0, 1, *x, 2]:
- y = 0
+NOT_YET_IMPLEMENTED_StmtMatch
# case black_test_patma_052
-match x:
- case [0]:
- y = 0
- case [1, 0] if (x := x[:0]):
- y = 1
- case [1, 0]:
- y = 2
+NOT_YET_IMPLEMENTED_StmtMatch
# case black_test_patma_191
-match w:
- case [x, y, *_]:
- z = 0
+NOT_YET_IMPLEMENTED_StmtMatch
# case black_test_patma_110
-match x:
- case -0.25 - 1.75j:
- y = 0
+NOT_YET_IMPLEMENTED_StmtMatch
# case black_test_patma_151
-match (x,):
- case [y]:
- z = 0
+NOT_YET_IMPLEMENTED_StmtMatch
# case black_test_patma_114
-match x:
- case A.B.C.D:
- y = 0
+NOT_YET_IMPLEMENTED_StmtMatch
# case black_test_patma_232
-match x:
- case None:
- y = 0
+NOT_YET_IMPLEMENTED_StmtMatch
# case black_test_patma_058
-match x:
- case 0:
- y = 0
+NOT_YET_IMPLEMENTED_StmtMatch
# case black_test_patma_233
-match x:
- case False:
- y = 0
+NOT_YET_IMPLEMENTED_StmtMatch
# case black_test_patma_078
-match x:
- case []:
- y = 0
- case [""]:
- y = 1
- case "":
- y = 2
+NOT_YET_IMPLEMENTED_StmtMatch
# case black_test_patma_156
-match x:
- case z:
- y = 0
+NOT_YET_IMPLEMENTED_StmtMatch
# case black_test_patma_189
-match w:
- case [x, y, *rest]:
- z = 0
+NOT_YET_IMPLEMENTED_StmtMatch
# case black_test_patma_042
-match x:
- case (0 as z) | (1 as z) | (2 as z) if z == x % 2:
- y = 0
+NOT_YET_IMPLEMENTED_StmtMatch
# case black_test_patma_034
-match x:
- case {0: [1, 2, {}]}:
- y = 0
- case {0: [1, 2, {}] | False} | {1: [[]]} | {0: [1, 2, {}]} | [] | "X" | {}:
- y = 1
- case []:
- y = 2
+NOT_YET_IMPLEMENTED_StmtMatch
```
## Ruff Output
```py
# Cases sampled from Lib/test/test_patma.py
# case black_test_patma_098
NOT_YET_IMPLEMENTED_StmtMatch
# case black_test_patma_142
NOT_YET_IMPLEMENTED_StmtMatch
# case black_test_patma_073
NOT_YET_IMPLEMENTED_StmtMatch
# case black_test_patma_006
NOT_YET_IMPLEMENTED_StmtMatch
# case black_test_patma_049
NOT_YET_IMPLEMENTED_StmtMatch
# case black_check_sequence_then_mapping
NOT_YET_IMPLEMENTED_StmtMatch
# case black_test_patma_035
NOT_YET_IMPLEMENTED_StmtMatch
# case black_test_patma_107
NOT_YET_IMPLEMENTED_StmtMatch
# case black_test_patma_097
NOT_YET_IMPLEMENTED_StmtMatch
# case black_test_patma_007
NOT_YET_IMPLEMENTED_StmtMatch
# case black_test_patma_154
NOT_YET_IMPLEMENTED_StmtMatch
# case black_test_patma_134
NOT_YET_IMPLEMENTED_StmtMatch
# case black_test_patma_185
NOT_YET_IMPLEMENTED_StmtMatch
# case black_test_patma_063
NOT_YET_IMPLEMENTED_StmtMatch
# case black_test_patma_248
NOT_YET_IMPLEMENTED_StmtMatch
# case black_test_patma_019
NOT_YET_IMPLEMENTED_StmtMatch
# case black_test_patma_052
NOT_YET_IMPLEMENTED_StmtMatch
# case black_test_patma_191
NOT_YET_IMPLEMENTED_StmtMatch
# case black_test_patma_110
NOT_YET_IMPLEMENTED_StmtMatch
# case black_test_patma_151
NOT_YET_IMPLEMENTED_StmtMatch
# case black_test_patma_114
NOT_YET_IMPLEMENTED_StmtMatch
# case black_test_patma_232
NOT_YET_IMPLEMENTED_StmtMatch
# case black_test_patma_058
NOT_YET_IMPLEMENTED_StmtMatch
# case black_test_patma_233
NOT_YET_IMPLEMENTED_StmtMatch
# case black_test_patma_078
NOT_YET_IMPLEMENTED_StmtMatch
# case black_test_patma_156
NOT_YET_IMPLEMENTED_StmtMatch
# case black_test_patma_189
NOT_YET_IMPLEMENTED_StmtMatch
# case black_test_patma_042
NOT_YET_IMPLEMENTED_StmtMatch
# case black_test_patma_034
NOT_YET_IMPLEMENTED_StmtMatch
```
## Black Output
```py
# Cases sampled from Lib/test/test_patma.py
# case black_test_patma_098
match x:
case -0j:
y = 0
# case black_test_patma_142
match x:
case bytes(z):
y = 0
# case black_test_patma_073
match x:
case 0 if 0:
y = 0
case 0 if 1:
y = 1
# case black_test_patma_006
match 3:
case 0 | 1 | 2 | 3:
x = True
# case black_test_patma_049
match x:
case [0, 1] | [1, 0]:
y = 0
# case black_check_sequence_then_mapping
match x:
case [*_]:
return "seq"
case {}:
return "map"
# case black_test_patma_035
match x:
case {0: [1, 2, {}]}:
y = 0
case {0: [1, 2, {}] | True} | {1: [[]]} | {0: [1, 2, {}]} | [] | "X" | {}:
y = 1
case []:
y = 2
# case black_test_patma_107
match x:
case 0.25 + 1.75j:
y = 0
# case black_test_patma_097
match x:
case -0j:
y = 0
# case black_test_patma_007
match 4:
case 0 | 1 | 2 | 3:
x = True
# case black_test_patma_154
match x:
case 0 if x:
y = 0
# case black_test_patma_134
match x:
case {1: 0}:
y = 0
case {0: 0}:
y = 1
case {**z}:
y = 2
# case black_test_patma_185
match Seq():
case [*_]:
y = 0
# case black_test_patma_063
match x:
case 1:
y = 0
case 1:
y = 1
# case black_test_patma_248
match x:
case {"foo": bar}:
y = bar
# case black_test_patma_019
match (0, 1, 2):
case [0, 1, *x, 2]:
y = 0
# case black_test_patma_052
match x:
case [0]:
y = 0
case [1, 0] if (x := x[:0]):
y = 1
case [1, 0]:
y = 2
# case black_test_patma_191
match w:
case [x, y, *_]:
z = 0
# case black_test_patma_110
match x:
case -0.25 - 1.75j:
y = 0
# case black_test_patma_151
match (x,):
case [y]:
z = 0
# case black_test_patma_114
match x:
case A.B.C.D:
y = 0
# case black_test_patma_232
match x:
case None:
y = 0
# case black_test_patma_058
match x:
case 0:
y = 0
# case black_test_patma_233
match x:
case False:
y = 0
# case black_test_patma_078
match x:
case []:
y = 0
case [""]:
y = 1
case "":
y = 2
# case black_test_patma_156
match x:
case z:
y = 0
# case black_test_patma_189
match w:
case [x, y, *rest]:
z = 0
# case black_test_patma_042
match x:
case (0 as z) | (1 as z) | (2 as z) if z == x % 2:
y = 0
# case black_test_patma_034
match x:
case {0: [1, 2, {}]}:
y = 0
case {0: [1, 2, {}] | False} | {1: [[]]} | {0: [1, 2, {}]} | [] | "X" | {}:
y = 1
case []:
y = 2
```

View file

@ -0,0 +1,443 @@
---
source: crates/ruff_python_formatter/tests/fixtures.rs
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/py_310/pattern_matching_extras.py
---
## Input
```py
import match
match something:
case [a as b]:
print(b)
case [a as b, c, d, e as f]:
print(f)
case Point(a as b):
print(b)
case Point(int() as x, int() as y):
print(x, y)
match = 1
case: int = re.match(something)
match re.match(case):
case type("match", match):
pass
case match:
pass
def func(match: case, case: match) -> case:
match Something():
case func(match, case):
...
case another:
...
match maybe, multiple:
case perhaps, 5:
pass
case perhaps, 6,:
pass
match more := (than, one), indeed,:
case _, (5, 6):
pass
case [[5], (6)], [7],:
pass
case _:
pass
match a, *b, c:
case [*_]:
assert "seq" == _
case {}:
assert "map" == b
match match(
case,
match(
match, case, match, looooooooooooooooooooooooooooooooooooong, match, case, match
),
case,
):
case case(
match=case,
case=re.match(
loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong
),
):
pass
case [a as match]:
pass
case case:
pass
match match:
case case:
pass
match a, *b(), c:
case d, *f, g:
pass
match something:
case {
"key": key as key_1,
"password": PASS.ONE | PASS.TWO | PASS.THREE as password,
}:
pass
case {"maybe": something(complicated as this) as that}:
pass
match something:
case 1 as a:
pass
case 2 as b, 3 as c:
pass
case 4 as d, (5 as e), (6 | 7 as g), *h:
pass
match bar1:
case Foo(aa=Callable() as aa, bb=int()):
print(bar1.aa, bar1.bb)
case _:
print("no match", "\n")
match bar1:
case Foo(
normal=x, perhaps=[list, {"x": d, "y": 1.0}] as y, otherwise=something, q=t as u
):
pass
```
## Black Differences
```diff
--- Black
+++ Ruff
@@ -1,119 +1,43 @@
-import match
+NOT_YET_IMPLEMENTED_StmtImport
-match something:
- case [a as b]:
- print(b)
- case [a as b, c, d, e as f]:
- print(f)
- case Point(a as b):
- print(b)
- case Point(int() as x, int() as y):
- print(x, y)
+NOT_YET_IMPLEMENTED_StmtMatch
match = 1
-case: int = re.match(something)
+NOT_YET_IMPLEMENTED_StmtAnnAssign
-match re.match(case):
- case type("match", match):
- pass
- case match:
- pass
+NOT_YET_IMPLEMENTED_StmtMatch
def func(match: case, case: match) -> case:
- match Something():
- case func(match, case):
- ...
- case another:
- ...
+ NOT_YET_IMPLEMENTED_StmtMatch
-match maybe, multiple:
- case perhaps, 5:
- pass
- case perhaps, 6,:
- pass
+NOT_YET_IMPLEMENTED_StmtMatch
-match more := (than, one), indeed,:
- case _, (5, 6):
- pass
- case [[5], (6)], [7],:
- pass
- case _:
- pass
+NOT_YET_IMPLEMENTED_StmtMatch
-match a, *b, c:
- case [*_]:
- assert "seq" == _
- case {}:
- assert "map" == b
+NOT_YET_IMPLEMENTED_StmtMatch
-match match(
- case,
- match(
- match, case, match, looooooooooooooooooooooooooooooooooooong, match, case, match
- ),
- case,
-):
- case case(
- match=case,
- case=re.match(
- loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong
- ),
- ):
- pass
-
- case [a as match]:
- pass
-
- case case:
- pass
+NOT_YET_IMPLEMENTED_StmtMatch
-match match:
- case case:
- pass
-
-
-match a, *b(), c:
- case d, *f, g:
- pass
+NOT_YET_IMPLEMENTED_StmtMatch
-match something:
- case {
- "key": key as key_1,
- "password": PASS.ONE | PASS.TWO | PASS.THREE as password,
- }:
- pass
- case {"maybe": something(complicated as this) as that}:
- pass
+NOT_YET_IMPLEMENTED_StmtMatch
-match something:
- case 1 as a:
- pass
+NOT_YET_IMPLEMENTED_StmtMatch
- case 2 as b, 3 as c:
- pass
- case 4 as d, (5 as e), (6 | 7 as g), *h:
- pass
+NOT_YET_IMPLEMENTED_StmtMatch
-match bar1:
- case Foo(aa=Callable() as aa, bb=int()):
- print(bar1.aa, bar1.bb)
- case _:
- print("no match", "\n")
+NOT_YET_IMPLEMENTED_StmtMatch
-match bar1:
- case Foo(
- normal=x, perhaps=[list, {"x": d, "y": 1.0}] as y, otherwise=something, q=t as u
- ):
- pass
+NOT_YET_IMPLEMENTED_StmtMatch
```
## Ruff Output
```py
NOT_YET_IMPLEMENTED_StmtImport
NOT_YET_IMPLEMENTED_StmtMatch
match = 1
NOT_YET_IMPLEMENTED_StmtAnnAssign
NOT_YET_IMPLEMENTED_StmtMatch
def func(match: case, case: match) -> case:
NOT_YET_IMPLEMENTED_StmtMatch
NOT_YET_IMPLEMENTED_StmtMatch
NOT_YET_IMPLEMENTED_StmtMatch
NOT_YET_IMPLEMENTED_StmtMatch
NOT_YET_IMPLEMENTED_StmtMatch
NOT_YET_IMPLEMENTED_StmtMatch
NOT_YET_IMPLEMENTED_StmtMatch
NOT_YET_IMPLEMENTED_StmtMatch
NOT_YET_IMPLEMENTED_StmtMatch
NOT_YET_IMPLEMENTED_StmtMatch
NOT_YET_IMPLEMENTED_StmtMatch
```
## Black Output
```py
import match
match something:
case [a as b]:
print(b)
case [a as b, c, d, e as f]:
print(f)
case Point(a as b):
print(b)
case Point(int() as x, int() as y):
print(x, y)
match = 1
case: int = re.match(something)
match re.match(case):
case type("match", match):
pass
case match:
pass
def func(match: case, case: match) -> case:
match Something():
case func(match, case):
...
case another:
...
match maybe, multiple:
case perhaps, 5:
pass
case perhaps, 6,:
pass
match more := (than, one), indeed,:
case _, (5, 6):
pass
case [[5], (6)], [7],:
pass
case _:
pass
match a, *b, c:
case [*_]:
assert "seq" == _
case {}:
assert "map" == b
match match(
case,
match(
match, case, match, looooooooooooooooooooooooooooooooooooong, match, case, match
),
case,
):
case case(
match=case,
case=re.match(
loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong
),
):
pass
case [a as match]:
pass
case case:
pass
match match:
case case:
pass
match a, *b(), c:
case d, *f, g:
pass
match something:
case {
"key": key as key_1,
"password": PASS.ONE | PASS.TWO | PASS.THREE as password,
}:
pass
case {"maybe": something(complicated as this) as that}:
pass
match something:
case 1 as a:
pass
case 2 as b, 3 as c:
pass
case 4 as d, (5 as e), (6 | 7 as g), *h:
pass
match bar1:
case Foo(aa=Callable() as aa, bb=int()):
print(bar1.aa, bar1.bb)
case _:
print("no match", "\n")
match bar1:
case Foo(
normal=x, perhaps=[list, {"x": d, "y": 1.0}] as y, otherwise=something, q=t as u
):
pass
```

View file

@ -0,0 +1,425 @@
---
source: crates/ruff_python_formatter/tests/fixtures.rs
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/py_310/pattern_matching_generic.py
---
## Input
```py
re.match()
match = a
with match() as match:
match = f"{match}"
re.match()
match = a
with match() as match:
match = f"{match}"
def get_grammars(target_versions: Set[TargetVersion]) -> List[Grammar]:
if not target_versions:
# No target_version specified, so try all grammars.
return [
# Python 3.7+
pygram.python_grammar_no_print_statement_no_exec_statement_async_keywords,
# Python 3.0-3.6
pygram.python_grammar_no_print_statement_no_exec_statement,
# Python 2.7 with future print_function import
pygram.python_grammar_no_print_statement,
# Python 2.7
pygram.python_grammar,
]
match match:
case case:
match match:
case case:
pass
if all(version.is_python2() for version in target_versions):
# Python 2-only code, so try Python 2 grammars.
return [
# Python 2.7 with future print_function import
pygram.python_grammar_no_print_statement,
# Python 2.7
pygram.python_grammar,
]
re.match()
match = a
with match() as match:
match = f"{match}"
def test_patma_139(self):
x = False
match x:
case bool(z):
y = 0
self.assertIs(x, False)
self.assertEqual(y, 0)
self.assertIs(z, x)
# Python 3-compatible code, so only try Python 3 grammar.
grammars = []
if supports_feature(target_versions, Feature.PATTERN_MATCHING):
# Python 3.10+
grammars.append(pygram.python_grammar_soft_keywords)
# If we have to parse both, try to parse async as a keyword first
if not supports_feature(
target_versions, Feature.ASYNC_IDENTIFIERS
) and not supports_feature(target_versions, Feature.PATTERN_MATCHING):
# Python 3.7-3.9
grammars.append(
pygram.python_grammar_no_print_statement_no_exec_statement_async_keywords
)
if not supports_feature(target_versions, Feature.ASYNC_KEYWORDS):
# Python 3.0-3.6
grammars.append(pygram.python_grammar_no_print_statement_no_exec_statement)
def test_patma_155(self):
x = 0
y = None
match x:
case 1e1000:
y = 0
self.assertEqual(x, 0)
self.assertIs(y, None)
x = range(3)
match x:
case [y, case as x, z]:
w = 0
# At least one of the above branches must have been taken, because every Python
# version has exactly one of the two 'ASYNC_*' flags
return grammars
def lib2to3_parse(src_txt: str, target_versions: Iterable[TargetVersion] = ()) -> Node:
"""Given a string with source, return the lib2to3 Node."""
if not src_txt.endswith("\n"):
src_txt += "\n"
grammars = get_grammars(set(target_versions))
re.match()
match = a
with match() as match:
match = f"{match}"
re.match()
match = a
with match() as match:
match = f"{match}"
```
## Black Differences
```diff
--- Black
+++ Ruff
@@ -1,12 +1,12 @@
re.match()
match = a
with match() as match:
- match = f"{match}"
+ match = NOT_YET_IMPLEMENTED_ExprJoinedStr
re.match()
match = a
with match() as match:
- match = f"{match}"
+ match = NOT_YET_IMPLEMENTED_ExprJoinedStr
def get_grammars(target_versions: Set[TargetVersion]) -> List[Grammar]:
@@ -23,13 +23,9 @@
pygram.python_grammar,
]
- match match:
- case case:
- match match:
- case case:
- pass
+ NOT_YET_IMPLEMENTED_StmtMatch
- if all(version.is_python2() for version in target_versions):
+ if all((i for i in [])):
# Python 2-only code, so try Python 2 grammars.
return [
# Python 2.7 with future print_function import
@@ -41,13 +37,11 @@
re.match()
match = a
with match() as match:
- match = f"{match}"
+ match = NOT_YET_IMPLEMENTED_ExprJoinedStr
def test_patma_139(self):
x = False
- match x:
- case bool(z):
- y = 0
+ NOT_YET_IMPLEMENTED_StmtMatch
self.assertIs(x, False)
self.assertEqual(y, 0)
self.assertIs(z, x)
@@ -72,16 +66,12 @@
def test_patma_155(self):
x = 0
y = None
- match x:
- case 1e1000:
- y = 0
+ NOT_YET_IMPLEMENTED_StmtMatch
self.assertEqual(x, 0)
self.assertIs(y, None)
x = range(3)
- match x:
- case [y, case as x, z]:
- w = 0
+ NOT_YET_IMPLEMENTED_StmtMatch
# At least one of the above branches must have been taken, because every Python
# version has exactly one of the two 'ASYNC_*' flags
@@ -91,7 +81,7 @@
def lib2to3_parse(src_txt: str, target_versions: Iterable[TargetVersion] = ()) -> Node:
"""Given a string with source, return the lib2to3 Node."""
if not src_txt.endswith("\n"):
- src_txt += "\n"
+ NOT_YET_IMPLEMENTED_StmtAugAssign
grammars = get_grammars(set(target_versions))
@@ -99,9 +89,9 @@
re.match()
match = a
with match() as match:
- match = f"{match}"
+ match = NOT_YET_IMPLEMENTED_ExprJoinedStr
re.match()
match = a
with match() as match:
- match = f"{match}"
+ match = NOT_YET_IMPLEMENTED_ExprJoinedStr
```
## Ruff Output
```py
re.match()
match = a
with match() as match:
match = NOT_YET_IMPLEMENTED_ExprJoinedStr
re.match()
match = a
with match() as match:
match = NOT_YET_IMPLEMENTED_ExprJoinedStr
def get_grammars(target_versions: Set[TargetVersion]) -> List[Grammar]:
if not target_versions:
# No target_version specified, so try all grammars.
return [
# Python 3.7+
pygram.python_grammar_no_print_statement_no_exec_statement_async_keywords,
# Python 3.0-3.6
pygram.python_grammar_no_print_statement_no_exec_statement,
# Python 2.7 with future print_function import
pygram.python_grammar_no_print_statement,
# Python 2.7
pygram.python_grammar,
]
NOT_YET_IMPLEMENTED_StmtMatch
if all((i for i in [])):
# Python 2-only code, so try Python 2 grammars.
return [
# Python 2.7 with future print_function import
pygram.python_grammar_no_print_statement,
# Python 2.7
pygram.python_grammar,
]
re.match()
match = a
with match() as match:
match = NOT_YET_IMPLEMENTED_ExprJoinedStr
def test_patma_139(self):
x = False
NOT_YET_IMPLEMENTED_StmtMatch
self.assertIs(x, False)
self.assertEqual(y, 0)
self.assertIs(z, x)
# Python 3-compatible code, so only try Python 3 grammar.
grammars = []
if supports_feature(target_versions, Feature.PATTERN_MATCHING):
# Python 3.10+
grammars.append(pygram.python_grammar_soft_keywords)
# If we have to parse both, try to parse async as a keyword first
if not supports_feature(
target_versions, Feature.ASYNC_IDENTIFIERS
) and not supports_feature(target_versions, Feature.PATTERN_MATCHING):
# Python 3.7-3.9
grammars.append(
pygram.python_grammar_no_print_statement_no_exec_statement_async_keywords
)
if not supports_feature(target_versions, Feature.ASYNC_KEYWORDS):
# Python 3.0-3.6
grammars.append(pygram.python_grammar_no_print_statement_no_exec_statement)
def test_patma_155(self):
x = 0
y = None
NOT_YET_IMPLEMENTED_StmtMatch
self.assertEqual(x, 0)
self.assertIs(y, None)
x = range(3)
NOT_YET_IMPLEMENTED_StmtMatch
# At least one of the above branches must have been taken, because every Python
# version has exactly one of the two 'ASYNC_*' flags
return grammars
def lib2to3_parse(src_txt: str, target_versions: Iterable[TargetVersion] = ()) -> Node:
"""Given a string with source, return the lib2to3 Node."""
if not src_txt.endswith("\n"):
NOT_YET_IMPLEMENTED_StmtAugAssign
grammars = get_grammars(set(target_versions))
re.match()
match = a
with match() as match:
match = NOT_YET_IMPLEMENTED_ExprJoinedStr
re.match()
match = a
with match() as match:
match = NOT_YET_IMPLEMENTED_ExprJoinedStr
```
## Black Output
```py
re.match()
match = a
with match() as match:
match = f"{match}"
re.match()
match = a
with match() as match:
match = f"{match}"
def get_grammars(target_versions: Set[TargetVersion]) -> List[Grammar]:
if not target_versions:
# No target_version specified, so try all grammars.
return [
# Python 3.7+
pygram.python_grammar_no_print_statement_no_exec_statement_async_keywords,
# Python 3.0-3.6
pygram.python_grammar_no_print_statement_no_exec_statement,
# Python 2.7 with future print_function import
pygram.python_grammar_no_print_statement,
# Python 2.7
pygram.python_grammar,
]
match match:
case case:
match match:
case case:
pass
if all(version.is_python2() for version in target_versions):
# Python 2-only code, so try Python 2 grammars.
return [
# Python 2.7 with future print_function import
pygram.python_grammar_no_print_statement,
# Python 2.7
pygram.python_grammar,
]
re.match()
match = a
with match() as match:
match = f"{match}"
def test_patma_139(self):
x = False
match x:
case bool(z):
y = 0
self.assertIs(x, False)
self.assertEqual(y, 0)
self.assertIs(z, x)
# Python 3-compatible code, so only try Python 3 grammar.
grammars = []
if supports_feature(target_versions, Feature.PATTERN_MATCHING):
# Python 3.10+
grammars.append(pygram.python_grammar_soft_keywords)
# If we have to parse both, try to parse async as a keyword first
if not supports_feature(
target_versions, Feature.ASYNC_IDENTIFIERS
) and not supports_feature(target_versions, Feature.PATTERN_MATCHING):
# Python 3.7-3.9
grammars.append(
pygram.python_grammar_no_print_statement_no_exec_statement_async_keywords
)
if not supports_feature(target_versions, Feature.ASYNC_KEYWORDS):
# Python 3.0-3.6
grammars.append(pygram.python_grammar_no_print_statement_no_exec_statement)
def test_patma_155(self):
x = 0
y = None
match x:
case 1e1000:
y = 0
self.assertEqual(x, 0)
self.assertIs(y, None)
x = range(3)
match x:
case [y, case as x, z]:
w = 0
# At least one of the above branches must have been taken, because every Python
# version has exactly one of the two 'ASYNC_*' flags
return grammars
def lib2to3_parse(src_txt: str, target_versions: Iterable[TargetVersion] = ()) -> Node:
"""Given a string with source, return the lib2to3 Node."""
if not src_txt.endswith("\n"):
src_txt += "\n"
grammars = get_grammars(set(target_versions))
re.match()
match = a
with match() as match:
match = f"{match}"
re.match()
match = a
with match() as match:
match = f"{match}"
```

View file

@ -0,0 +1,343 @@
---
source: crates/ruff_python_formatter/tests/fixtures.rs
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/py_310/pattern_matching_simple.py
---
## Input
```py
# Cases sampled from PEP 636 examples
match command.split():
case [action, obj]:
... # interpret action, obj
match command.split():
case [action]:
... # interpret single-verb action
case [action, obj]:
... # interpret action, obj
match command.split():
case ["quit"]:
print("Goodbye!")
quit_game()
case ["look"]:
current_room.describe()
case ["get", obj]:
character.get(obj, current_room)
case ["go", direction]:
current_room = current_room.neighbor(direction)
# The rest of your commands go here
match command.split():
case ["drop", *objects]:
for obj in objects:
character.drop(obj, current_room)
# The rest of your commands go here
match command.split():
case ["quit"]:
pass
case ["go", direction]:
print("Going:", direction)
case ["drop", *objects]:
print("Dropping: ", *objects)
case _:
print(f"Sorry, I couldn't understand {command!r}")
match command.split():
case ["north"] | ["go", "north"]:
current_room = current_room.neighbor("north")
case ["get", obj] | ["pick", "up", obj] | ["pick", obj, "up"]:
... # Code for picking up the given object
match command.split():
case ["go", ("north" | "south" | "east" | "west")]:
current_room = current_room.neighbor(...)
# how do I know which direction to go?
match command.split():
case ["go", ("north" | "south" | "east" | "west") as direction]:
current_room = current_room.neighbor(direction)
match command.split():
case ["go", direction] if direction in current_room.exits:
current_room = current_room.neighbor(direction)
case ["go", _]:
print("Sorry, you can't go that way")
match event.get():
case Click(position=(x, y)):
handle_click_at(x, y)
case KeyPress(key_name="Q") | Quit():
game.quit()
case KeyPress(key_name="up arrow"):
game.go_north()
case KeyPress():
pass # Ignore other keystrokes
case other_event:
raise ValueError(f"Unrecognized event: {other_event}")
match event.get():
case Click((x, y), button=Button.LEFT): # This is a left click
handle_click_at(x, y)
case Click():
pass # ignore other clicks
def where_is(point):
match point:
case Point(x=0, y=0):
print("Origin")
case Point(x=0, y=y):
print(f"Y={y}")
case Point(x=x, y=0):
print(f"X={x}")
case Point():
print("Somewhere else")
case _:
print("Not a point")
```
## Black Differences
```diff
--- Black
+++ Ruff
@@ -1,92 +1,27 @@
# Cases sampled from PEP 636 examples
-match command.split():
- case [action, obj]:
- ... # interpret action, obj
+NOT_YET_IMPLEMENTED_StmtMatch
-match command.split():
- case [action]:
- ... # interpret single-verb action
- case [action, obj]:
- ... # interpret action, obj
+NOT_YET_IMPLEMENTED_StmtMatch
-match command.split():
- case ["quit"]:
- print("Goodbye!")
- quit_game()
- case ["look"]:
- current_room.describe()
- case ["get", obj]:
- character.get(obj, current_room)
- case ["go", direction]:
- current_room = current_room.neighbor(direction)
- # The rest of your commands go here
+NOT_YET_IMPLEMENTED_StmtMatch
-match command.split():
- case ["drop", *objects]:
- for obj in objects:
- character.drop(obj, current_room)
- # The rest of your commands go here
+NOT_YET_IMPLEMENTED_StmtMatch
-match command.split():
- case ["quit"]:
- pass
- case ["go", direction]:
- print("Going:", direction)
- case ["drop", *objects]:
- print("Dropping: ", *objects)
- case _:
- print(f"Sorry, I couldn't understand {command!r}")
+NOT_YET_IMPLEMENTED_StmtMatch
-match command.split():
- case ["north"] | ["go", "north"]:
- current_room = current_room.neighbor("north")
- case ["get", obj] | ["pick", "up", obj] | ["pick", obj, "up"]:
- ... # Code for picking up the given object
+NOT_YET_IMPLEMENTED_StmtMatch
-match command.split():
- case ["go", ("north" | "south" | "east" | "west")]:
- current_room = current_room.neighbor(...)
- # how do I know which direction to go?
+NOT_YET_IMPLEMENTED_StmtMatch
-match command.split():
- case ["go", ("north" | "south" | "east" | "west") as direction]:
- current_room = current_room.neighbor(direction)
+NOT_YET_IMPLEMENTED_StmtMatch
-match command.split():
- case ["go", direction] if direction in current_room.exits:
- current_room = current_room.neighbor(direction)
- case ["go", _]:
- print("Sorry, you can't go that way")
+NOT_YET_IMPLEMENTED_StmtMatch
-match event.get():
- case Click(position=(x, y)):
- handle_click_at(x, y)
- case KeyPress(key_name="Q") | Quit():
- game.quit()
- case KeyPress(key_name="up arrow"):
- game.go_north()
- case KeyPress():
- pass # Ignore other keystrokes
- case other_event:
- raise ValueError(f"Unrecognized event: {other_event}")
+NOT_YET_IMPLEMENTED_StmtMatch
-match event.get():
- case Click((x, y), button=Button.LEFT): # This is a left click
- handle_click_at(x, y)
- case Click():
- pass # ignore other clicks
+NOT_YET_IMPLEMENTED_StmtMatch
def where_is(point):
- match point:
- case Point(x=0, y=0):
- print("Origin")
- case Point(x=0, y=y):
- print(f"Y={y}")
- case Point(x=x, y=0):
- print(f"X={x}")
- case Point():
- print("Somewhere else")
- case _:
- print("Not a point")
+ NOT_YET_IMPLEMENTED_StmtMatch
```
## Ruff Output
```py
# Cases sampled from PEP 636 examples
NOT_YET_IMPLEMENTED_StmtMatch
NOT_YET_IMPLEMENTED_StmtMatch
NOT_YET_IMPLEMENTED_StmtMatch
NOT_YET_IMPLEMENTED_StmtMatch
NOT_YET_IMPLEMENTED_StmtMatch
NOT_YET_IMPLEMENTED_StmtMatch
NOT_YET_IMPLEMENTED_StmtMatch
NOT_YET_IMPLEMENTED_StmtMatch
NOT_YET_IMPLEMENTED_StmtMatch
NOT_YET_IMPLEMENTED_StmtMatch
NOT_YET_IMPLEMENTED_StmtMatch
def where_is(point):
NOT_YET_IMPLEMENTED_StmtMatch
```
## Black Output
```py
# Cases sampled from PEP 636 examples
match command.split():
case [action, obj]:
... # interpret action, obj
match command.split():
case [action]:
... # interpret single-verb action
case [action, obj]:
... # interpret action, obj
match command.split():
case ["quit"]:
print("Goodbye!")
quit_game()
case ["look"]:
current_room.describe()
case ["get", obj]:
character.get(obj, current_room)
case ["go", direction]:
current_room = current_room.neighbor(direction)
# The rest of your commands go here
match command.split():
case ["drop", *objects]:
for obj in objects:
character.drop(obj, current_room)
# The rest of your commands go here
match command.split():
case ["quit"]:
pass
case ["go", direction]:
print("Going:", direction)
case ["drop", *objects]:
print("Dropping: ", *objects)
case _:
print(f"Sorry, I couldn't understand {command!r}")
match command.split():
case ["north"] | ["go", "north"]:
current_room = current_room.neighbor("north")
case ["get", obj] | ["pick", "up", obj] | ["pick", obj, "up"]:
... # Code for picking up the given object
match command.split():
case ["go", ("north" | "south" | "east" | "west")]:
current_room = current_room.neighbor(...)
# how do I know which direction to go?
match command.split():
case ["go", ("north" | "south" | "east" | "west") as direction]:
current_room = current_room.neighbor(direction)
match command.split():
case ["go", direction] if direction in current_room.exits:
current_room = current_room.neighbor(direction)
case ["go", _]:
print("Sorry, you can't go that way")
match event.get():
case Click(position=(x, y)):
handle_click_at(x, y)
case KeyPress(key_name="Q") | Quit():
game.quit()
case KeyPress(key_name="up arrow"):
game.go_north()
case KeyPress():
pass # Ignore other keystrokes
case other_event:
raise ValueError(f"Unrecognized event: {other_event}")
match event.get():
case Click((x, y), button=Button.LEFT): # This is a left click
handle_click_at(x, y)
case Click():
pass # ignore other clicks
def where_is(point):
match point:
case Point(x=0, y=0):
print("Origin")
case Point(x=0, y=y):
print(f"Y={y}")
case Point(x=x, y=0):
print(f"X={x}")
case Point():
print("Somewhere else")
case _:
print("Not a point")
```

View file

@ -0,0 +1,186 @@
---
source: crates/ruff_python_formatter/tests/fixtures.rs
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/py_310/pattern_matching_style.py
---
## Input
```py
match something:
case b(): print(1+1)
case c(
very_complex=True,
perhaps_even_loooooooooooooooooooooooooooooooooooooong=- 1
): print(1)
case c(
very_complex=True,
perhaps_even_loooooooooooooooooooooooooooooooooooooong=-1,
): print(2)
case a: pass
match(
arg # comment
)
match(
)
match(
)
case(
arg # comment
)
case(
)
case(
)
re.match(
something # fast
)
re.match(
)
match match(
):
case case(
arg, # comment
):
pass
```
## Black Differences
```diff
--- Black
+++ Ruff
@@ -1,35 +1,24 @@
-match something:
- case b():
- print(1 + 1)
- case c(
- very_complex=True, perhaps_even_loooooooooooooooooooooooooooooooooooooong=-1
- ):
- print(1)
- case c(
- very_complex=True,
- perhaps_even_loooooooooooooooooooooooooooooooooooooong=-1,
- ):
- print(2)
- case a:
- pass
+NOT_YET_IMPLEMENTED_StmtMatch
-match(arg) # comment
+match(
+ arg, # comment
+)
match()
match()
-case(arg) # comment
+case(
+ arg, # comment
+)
case()
case()
-re.match(something) # fast
+re.match(
+ something, # fast
+)
re.match()
-match match():
- case case(
- arg, # comment
- ):
- pass
+NOT_YET_IMPLEMENTED_StmtMatch
```
## Ruff Output
```py
NOT_YET_IMPLEMENTED_StmtMatch
match(
arg, # comment
)
match()
match()
case(
arg, # comment
)
case()
case()
re.match(
something, # fast
)
re.match()
NOT_YET_IMPLEMENTED_StmtMatch
```
## Black Output
```py
match something:
case b():
print(1 + 1)
case c(
very_complex=True, perhaps_even_loooooooooooooooooooooooooooooooooooooong=-1
):
print(1)
case c(
very_complex=True,
perhaps_even_loooooooooooooooooooooooooooooooooooooong=-1,
):
print(2)
case a:
pass
match(arg) # comment
match()
match()
case(arg) # comment
case()
case()
re.match(something) # fast
re.match()
match match():
case case(
arg, # comment
):
pass
```

View file

@ -0,0 +1,96 @@
---
source: crates/ruff_python_formatter/tests/fixtures.rs
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/py_310/pep_572_py310.py
---
## Input
```py
# Unparenthesized walruses are now allowed in indices since Python 3.10.
x[a:=0]
x[a:=0, b:=1]
x[5, b:=0]
# Walruses are allowed inside generator expressions on function calls since 3.10.
if any(match := pattern_error.match(s) for s in buffer):
if match.group(2) == data_not_available:
# Error OK to ignore.
pass
f(a := b + c for c in range(10))
f((a := b + c for c in range(10)), x)
f(y=(a := b + c for c in range(10)))
f(x, (a := b + c for c in range(10)), y=z, **q)
```
## Black Differences
```diff
--- Black
+++ Ruff
@@ -1,15 +1,15 @@
# Unparenthesized walruses are now allowed in indices since Python 3.10.
-x[a:=0]
-x[a:=0, b:=1]
-x[5, b:=0]
+x[NOT_YET_IMPLEMENTED_ExprNamedExpr]
+x[NOT_YET_IMPLEMENTED_ExprNamedExpr, NOT_YET_IMPLEMENTED_ExprNamedExpr]
+x[5, NOT_YET_IMPLEMENTED_ExprNamedExpr]
# Walruses are allowed inside generator expressions on function calls since 3.10.
-if any(match := pattern_error.match(s) for s in buffer):
+if any((i for i in [])):
if match.group(2) == data_not_available:
# Error OK to ignore.
pass
-f(a := b + c for c in range(10))
-f((a := b + c for c in range(10)), x)
-f(y=(a := b + c for c in range(10)))
-f(x, (a := b + c for c in range(10)), y=z, **q)
+f((i for i in []))
+f((i for i in []), x)
+f(y=(i for i in []))
+f(x, (i for i in []), y=z, **q)
```
## Ruff Output
```py
# Unparenthesized walruses are now allowed in indices since Python 3.10.
x[NOT_YET_IMPLEMENTED_ExprNamedExpr]
x[NOT_YET_IMPLEMENTED_ExprNamedExpr, NOT_YET_IMPLEMENTED_ExprNamedExpr]
x[5, NOT_YET_IMPLEMENTED_ExprNamedExpr]
# Walruses are allowed inside generator expressions on function calls since 3.10.
if any((i for i in [])):
if match.group(2) == data_not_available:
# Error OK to ignore.
pass
f((i for i in []))
f((i for i in []), x)
f(y=(i for i in []))
f(x, (i for i in []), y=z, **q)
```
## Black Output
```py
# Unparenthesized walruses are now allowed in indices since Python 3.10.
x[a:=0]
x[a:=0, b:=1]
x[5, b:=0]
# Walruses are allowed inside generator expressions on function calls since 3.10.
if any(match := pattern_error.match(s) for s in buffer):
if match.group(2) == data_not_available:
# Error OK to ignore.
pass
f(a := b + c for c in range(10))
f((a := b + c for c in range(10)), x)
f(y=(a := b + c for c in range(10)))
f(x, (a := b + c for c in range(10)), y=z, **q)
```

View file

@ -0,0 +1,76 @@
---
source: crates/ruff_python_formatter/tests/fixtures.rs
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/py_310/remove_newline_after_match.py
---
## Input
```py
def http_status(status):
match status:
case 400:
return "Bad request"
case 401:
return "Unauthorized"
case 403:
return "Forbidden"
case 404:
return "Not found"
```
## Black Differences
```diff
--- Black
+++ Ruff
@@ -1,13 +1,2 @@
def http_status(status):
- match status:
- case 400:
- return "Bad request"
-
- case 401:
- return "Unauthorized"
-
- case 403:
- return "Forbidden"
-
- case 404:
- return "Not found"
+ NOT_YET_IMPLEMENTED_StmtMatch
```
## Ruff Output
```py
def http_status(status):
NOT_YET_IMPLEMENTED_StmtMatch
```
## Black Output
```py
def http_status(status):
match status:
case 400:
return "Bad request"
case 401:
return "Unauthorized"
case 403:
return "Forbidden"
case 404:
return "Not found"
```

Some files were not shown because too many files have changed in this diff Show more