diff --git a/crates/ruff_python_formatter/src/module/mod_module.rs b/crates/ruff_python_formatter/src/module/mod_module.rs index a2d0370b5c223e..79a7054eb82098 100644 --- a/crates/ruff_python_formatter/src/module/mod_module.rs +++ b/crates/ruff_python_formatter/src/module/mod_module.rs @@ -1,8 +1,9 @@ -use crate::AsFormat; -use crate::{FormatNodeRule, PyFormatter}; +use crate::builders::{JoinNodesBuilder, PyFormatterExtensions}; +use crate::context::NodeLevel; +use crate::statement::suite::SuiteLevel; +use crate::{AsFormat, FormatNodeRule, PyFormatter}; use ruff_formatter::prelude::hard_line_break; -use ruff_formatter::{write, Buffer, FormatResult}; - +use ruff_formatter::{write, Buffer, Format, FormatResult}; use rustpython_parser::ast::ModModule; #[derive(Default)] @@ -10,9 +11,12 @@ pub struct FormatModModule; impl FormatNodeRule for FormatModModule { fn fmt_fields(&self, item: &ModModule, f: &mut PyFormatter) -> FormatResult<()> { - for stmt in &item.body { - write!(f, [stmt.format(), hard_line_break()])?; - } - Ok(()) + write!( + f, + [ + item.body.format().with_options(SuiteLevel::TopLevel), + hard_line_break() + ] + ) } } diff --git a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__attribute_access_on_number_literals_py.snap b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__attribute_access_on_number_literals_py.snap index 2849790d1fa43b..0128d6ed458e3f 100644 --- a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__attribute_access_on_number_literals_py.snap +++ b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__attribute_access_on_number_literals_py.snap @@ -35,7 +35,7 @@ y = 100(no) ```diff --- Black +++ Ruff -@@ -1,22 +1,20 @@ +@@ -1,21 +1,21 @@ -x = (123456789).bit_count() +x = 123456789 .bit_count() x = (123456).__abs__() @@ -53,8 +53,6 @@ y = 100(no) -x = 0o777.real -x = (0.000000006).hex() -x = -100.0000j -- --if (10).real: +x = .1.is_integer() +x = 1. .imag +x = 1E+1.imag @@ -69,11 +67,12 @@ y = 100(no) +x = 0O777 .real +x = 0.000000006 .hex() +x = -100.0000J + +-if (10).real: +if 10 .real: ... -- + y = 100[no] - y = 100(no) ``` ## Ruff Output @@ -95,8 +94,10 @@ x = 0B1011 .conjugate() x = 0O777 .real x = 0.000000006 .hex() x = -100.0000J + if 10 .real: ... + y = 100[no] y = 100(no) ``` diff --git a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__class_blank_parentheses_py.snap b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__class_blank_parentheses_py.snap index 5e1f3eff025dbd..c40c09ee3a2536 100644 --- a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__class_blank_parentheses_py.snap +++ b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__class_blank_parentheses_py.snap @@ -36,12 +36,12 @@ class NormalClass ( ```diff --- Black +++ Ruff -@@ -1,30 +1,21 @@ +@@ -1,16 +1,16 @@ -class SimpleClassWithBlankParentheses: +class SimpleClassWithBlankParentheses(): pass -- -- + + -class ClassWithSpaceParentheses: +class ClassWithSpaceParentheses ( ): first_test_data = 90 @@ -49,24 +49,22 @@ class NormalClass ( - def test_func(self): return None -- -- + + class ClassWithEmptyFunc(object): + def func_with_blank_parentheses(): return 5 -- -- - def public_func_with_blank_parentheses(): - return None -- -- + +@@ -20,11 +20,12 @@ + + def class_under_the_func_with_blank_parentheses(): - class InsideFunc: + class InsideFunc(): pass -- -- + + -class NormalClass: +class NormalClass ( +): @@ -80,20 +78,30 @@ class NormalClass ( ```py class SimpleClassWithBlankParentheses(): pass + + class ClassWithSpaceParentheses ( ): first_test_data = 90 second_test_data = 100 def test_func(self): return None + + class ClassWithEmptyFunc(object): def func_with_blank_parentheses(): return 5 + + def public_func_with_blank_parentheses(): return None + + def class_under_the_func_with_blank_parentheses(): class InsideFunc(): pass + + class NormalClass ( ): def func_for_testing(self, first, second): diff --git a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__class_methods_new_line_py.snap b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__class_methods_new_line_py.snap index 5cdc7dd0c2fea5..c569564e5c173d 100644 --- a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__class_methods_new_line_py.snap +++ b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__class_methods_new_line_py.snap @@ -113,38 +113,22 @@ class ClassWithDecoInitAndVarsAndDocstringWithInner2: ```diff --- Black +++ Ruff -@@ -1,165 +1,100 @@ - class ClassSimplest: - pass -- -- - class ClassWithSingleField: - a = 1 -- -- - class ClassWithJustTheDocstring: - """Just a docstring.""" -- -- - class ClassWithInit: - def __init__(self): - pass -- -- +@@ -17,23 +17,19 @@ + class ClassWithTheDocstringAndInit: """Just a docstring.""" - def __init__(self): pass -- -- + + class ClassWithInitAndVars: cls_var = 100 - def __init__(self): pass -- -- + + class ClassWithInitAndVarsAndDocstring: """Test class""" - @@ -152,22 +136,17 @@ class ClassWithDecoInitAndVarsAndDocstringWithInner2: - def __init__(self): pass -- -- - class ClassWithDecoInit: - @deco - def __init__(self): - pass -- -- + +@@ -46,7 +42,6 @@ + class ClassWithDecoInitAndVars: cls_var = 100 - @deco def __init__(self): pass -- -- +@@ -54,9 +49,7 @@ + class ClassWithDecoInitAndVarsAndDocstring: """Test class""" - @@ -176,43 +155,37 @@ class ClassWithDecoInitAndVarsAndDocstringWithInner2: @deco def __init__(self): pass -- -- - class ClassSimplestWithInner: - class Inner: - pass -- -- +@@ -70,21 +63,18 @@ class ClassSimplestWithInnerWithDocstring: class Inner: """Just a docstring.""" - def __init__(self): pass -- -- + + class ClassWithSingleFieldWithInner: a = 1 - class Inner: pass -- -- + + class ClassWithJustTheDocstringWithInner: """Just a docstring.""" - class Inner: pass -- -- + +@@ -92,29 +82,23 @@ class ClassWithInitWithInner: class Inner: pass - def __init__(self): pass -- -- + + class ClassWithInitAndVarsWithInner: cls_var = 100 - @@ -221,8 +194,8 @@ class ClassWithDecoInitAndVarsAndDocstringWithInner2: - def __init__(self): pass -- -- + + class ClassWithInitAndVarsAndDocstringWithInner: """Test class""" - @@ -233,8 +206,8 @@ class ClassWithDecoInitAndVarsAndDocstringWithInner2: - def __init__(self): pass -- -- + +@@ -122,7 +106,6 @@ class ClassWithDecoInitWithInner: class Inner: pass @@ -242,8 +215,8 @@ class ClassWithDecoInitAndVarsAndDocstringWithInner2: @deco def __init__(self): pass -- -- +@@ -130,10 +113,8 @@ + class ClassWithDecoInitAndVarsWithInner: cls_var = 100 - @@ -253,8 +226,8 @@ class ClassWithDecoInitAndVarsAndDocstringWithInner2: @deco def __init__(self): pass -- -- +@@ -141,12 +122,9 @@ + class ClassWithDecoInitAndVarsAndDocstringWithInner: """Test class""" - @@ -266,8 +239,8 @@ class ClassWithDecoInitAndVarsAndDocstringWithInner2: @deco def __init__(self): pass -- -- +@@ -154,12 +132,9 @@ + class ClassWithDecoInitAndVarsAndDocstringWithInner2: """Test class""" - @@ -286,68 +259,100 @@ class ClassWithDecoInitAndVarsAndDocstringWithInner2: ```py class ClassSimplest: pass + + class ClassWithSingleField: a = 1 + + class ClassWithJustTheDocstring: """Just a docstring.""" + + class ClassWithInit: def __init__(self): pass + + class ClassWithTheDocstringAndInit: """Just a docstring.""" def __init__(self): pass + + class ClassWithInitAndVars: cls_var = 100 def __init__(self): pass + + class ClassWithInitAndVarsAndDocstring: """Test class""" cls_var = 100 def __init__(self): pass + + class ClassWithDecoInit: @deco def __init__(self): pass + + class ClassWithDecoInitAndVars: cls_var = 100 @deco def __init__(self): pass + + class ClassWithDecoInitAndVarsAndDocstring: """Test class""" cls_var = 100 @deco def __init__(self): pass + + class ClassSimplestWithInner: class Inner: pass + + class ClassSimplestWithInnerWithDocstring: class Inner: """Just a docstring.""" def __init__(self): pass + + class ClassWithSingleFieldWithInner: a = 1 class Inner: pass + + class ClassWithJustTheDocstringWithInner: """Just a docstring.""" class Inner: pass + + class ClassWithInitWithInner: class Inner: pass def __init__(self): pass + + class ClassWithInitAndVarsWithInner: cls_var = 100 class Inner: pass def __init__(self): pass + + class ClassWithInitAndVarsAndDocstringWithInner: """Test class""" cls_var = 100 @@ -355,12 +360,16 @@ class ClassWithInitAndVarsAndDocstringWithInner: pass def __init__(self): pass + + class ClassWithDecoInitWithInner: class Inner: pass @deco def __init__(self): pass + + class ClassWithDecoInitAndVarsWithInner: cls_var = 100 class Inner: @@ -368,6 +377,8 @@ class ClassWithDecoInitAndVarsWithInner: @deco def __init__(self): pass + + class ClassWithDecoInitAndVarsAndDocstringWithInner: """Test class""" cls_var = 100 @@ -376,6 +387,8 @@ class ClassWithDecoInitAndVarsAndDocstringWithInner: @deco def __init__(self): pass + + class ClassWithDecoInitAndVarsAndDocstringWithInner2: """Test class""" class Inner: diff --git a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__collections_py.snap b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__collections_py.snap index 5daf501dc3c870..50f5ab1f05d413 100644 --- a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__collections_py.snap +++ b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__collections_py.snap @@ -84,9 +84,9 @@ if True: ```diff --- Black +++ Ruff -@@ -1,99 +1,61 @@ +@@ -1,75 +1,49 @@ import core, time, a -- + from . import A, B, C - # keeps existing trailing comma @@ -104,7 +104,7 @@ if True: from foo import ( xyzzy as magic, ) -- + -a = { - 1, - 2, @@ -162,24 +162,22 @@ if True: pass for (x,) in (1,), (2,), (3,): pass -- + -[ - 1, - 2, - 3, -] -- --division_result_tuple = (6 / 2,) +[1, 2, 3,] + +-division_result_tuple = (6 / 2,) +division_result_tuple = (6/2,) print("foo %r", (foo.bar,)) -- + if True: - IGNORED_TYPES_FOR_ATTRIBUTE_CHECKING = ( - Config.IGNORED_TYPES_FOR_ATTRIBUTE_CHECKING - | {pylons.controllers.WSGIController} +@@ -79,21 +53,15 @@ ) -- + if True: - ec2client.get_waiter("instance_stopped").wait( + ec2client.get_waiter('instance_stopped').wait( @@ -210,6 +208,7 @@ if True: ```py import core, time, a + from . import A, B, C # keeps existing trailing comma from foo import ( @@ -224,6 +223,7 @@ from foo import ( from foo import ( xyzzy as magic, ) + a = {1,2,3,} b = { 1,2, @@ -249,14 +249,18 @@ for x in (1,): pass for (x,) in (1,), (2,), (3,): pass + [1, 2, 3,] + division_result_tuple = (6/2,) print("foo %r", (foo.bar,)) + if True: IGNORED_TYPES_FOR_ATTRIBUTE_CHECKING = ( Config.IGNORED_TYPES_FOR_ATTRIBUTE_CHECKING | {pylons.controllers.WSGIController} ) + if True: ec2client.get_waiter('instance_stopped').wait( InstanceIds=[instance.id], diff --git a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__comment_after_escaped_newline_py.snap b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__comment_after_escaped_newline_py.snap index 86d56db4337cbb..5633eef26a402f 100644 --- a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__comment_after_escaped_newline_py.snap +++ b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__comment_after_escaped_newline_py.snap @@ -22,13 +22,13 @@ def bobtwo(): \ ```diff --- Black +++ Ruff -@@ -1,6 +1,7 @@ +@@ -1,6 +1,9 @@ -def bob(): # pylint: disable=W9016 +def bob(): \ + # pylint: disable=W9016 pass -- -- + + -def bobtwo(): # some comment here +def bobtwo(): \ + \ @@ -42,6 +42,8 @@ def bobtwo(): \ def bob(): \ # pylint: disable=W9016 pass + + def bobtwo(): \ \ # some comment here diff --git a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__comments2_py.snap b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__comments2_py.snap index 808c55756f1d2d..cd228ca42b7276 100644 --- a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__comments2_py.snap +++ b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__comments2_py.snap @@ -178,7 +178,7 @@ instruction()#comment with bad spacing ```diff --- Black +++ Ruff -@@ -1,39 +1,38 @@ +@@ -1,39 +1,40 @@ from com.my_lovely_company.my_lovely_team.my_lovely_project.my_lovely_component import ( - MyLovelyCompanyTeamProjectComponent, # NOT DRY + MyLovelyCompanyTeamProjectComponent # NOT DRY @@ -187,7 +187,7 @@ instruction()#comment with bad spacing - MyLovelyCompanyTeamProjectComponent as component, # DRY + MyLovelyCompanyTeamProjectComponent as component # DRY ) -- + # Please keep __all__ alphabetized within each category. __all__ = [ @@ -227,7 +227,7 @@ instruction()#comment with bad spacing + 'NamedTuple', # Not really a type. + 'Generator', ] -- + not_shareables = [ # singletons True, @@ -238,11 +238,10 @@ instruction()#comment with bad spacing # builtin types and objects type, object, -@@ -47,21 +46,21 @@ - Cheese("Wensleydale"), +@@ -48,20 +49,23 @@ SubBytes(b"spam"), ] -- + -if "PYTHON" in os.environ: +if 'PYTHON' in os.environ: add_compiler(compiler_from_env()) @@ -252,8 +251,8 @@ instruction()#comment with bad spacing + # add_compiler(compiler) add_compiler(compilers[(7.0, 32)]) - # add_compiler(compilers[(7.1, 64)]) -- -- + + # Comment before function. def inline_comments_in_brackets_ruin_everything(): if typedargslist: @@ -267,7 +266,7 @@ instruction()#comment with bad spacing children[0], body, children[-1], # type: ignore -@@ -73,49 +72,42 @@ +@@ -73,49 +77,42 @@ parameters.children[-1], # )2 ] parameters.children = [parameters.what_if_this_was_actually_long.children[0], body, parameters.children[-1]] # type: ignore @@ -340,7 +339,7 @@ instruction()#comment with bad spacing ] lcomp2 = [ # hello -@@ -127,7 +119,7 @@ +@@ -127,7 +124,7 @@ ] lcomp3 = [ # This one is actually too long to fit in a single line. @@ -349,7 +348,7 @@ instruction()#comment with bad spacing # yup for element in collection.select_elements() # right -@@ -140,28 +132,20 @@ +@@ -140,25 +137,23 @@ # and round and round we go # and round and round we go @@ -363,8 +362,8 @@ instruction()#comment with bad spacing + Leaf(token.NEWLINE, '\n') # FIXME: \r\n? + ], ) -- -- + + -CONFIG_FILES = ( - [ - CONFIG_FILE, @@ -372,20 +371,17 @@ instruction()#comment with bad spacing - + SHARED_CONFIG_FILES - + USER_CONFIG_FILES -) # type: Final -- -- +CONFIG_FILES = [CONFIG_FILE, ] + SHARED_CONFIG_FILES + USER_CONFIG_FILES # type: Final + + class Test: def _init_host(self, parsed) -> None: - if parsed.hostname is None or not parsed.hostname.strip(): # type: ignore + if (parsed.hostname is None or # type: ignore + not parsed.hostname.strip()): pass -- -- - ####################### - ### SECTION COMMENT ### - ####################### + + ``` ## Ruff Output @@ -397,6 +393,7 @@ from com.my_lovely_company.my_lovely_team.my_lovely_project.my_lovely_component from com.my_lovely_company.my_lovely_team.my_lovely_project.my_lovely_component import ( MyLovelyCompanyTeamProjectComponent as component # DRY ) + # Please keep __all__ alphabetized within each category. __all__ = [ @@ -421,6 +418,7 @@ __all__ = [ 'NamedTuple', # Not really a type. 'Generator', ] + not_shareables = [ # singletons True, @@ -439,12 +437,15 @@ not_shareables = [ Cheese("Wensleydale"), SubBytes(b"spam"), ] + if 'PYTHON' in os.environ: add_compiler(compiler_from_env()) else: # for compiler in compilers.values(): # add_compiler(compiler) add_compiler(compilers[(7.0, 32)]) + + # Comment before function. def inline_comments_in_brackets_ruin_everything(): if typedargslist: @@ -533,12 +534,18 @@ short Leaf(token.NEWLINE, '\n') # FIXME: \r\n? ], ) + + CONFIG_FILES = [CONFIG_FILE, ] + SHARED_CONFIG_FILES + USER_CONFIG_FILES # type: Final + + class Test: def _init_host(self, parsed) -> None: if (parsed.hostname is None or # type: ignore not parsed.hostname.strip()): pass + + ####################### ### SECTION COMMENT ### ####################### diff --git a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__comments4_py.snap b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__comments4_py.snap deleted file mode 100644 index 77be147ea121d3..00000000000000 --- a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__comments4_py.snap +++ /dev/null @@ -1,338 +0,0 @@ ---- -source: crates/ruff_python_formatter/src/lib.rs -expression: snapshot -input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/comments4.py ---- -## Input - -```py -from com.my_lovely_company.my_lovely_team.my_lovely_project.my_lovely_component import ( - MyLovelyCompanyTeamProjectComponent, # NOT DRY -) -from com.my_lovely_company.my_lovely_team.my_lovely_project.my_lovely_component import ( - MyLovelyCompanyTeamProjectComponent as component, # DRY -) - - -class C: - @pytest.mark.parametrize( - ("post_data", "message"), - [ - # metadata_version errors. - ( - {}, - "None is an invalid value for Metadata-Version. Error: This field is" - " required. see" - " https://packaging.python.org/specifications/core-metadata", - ), - ( - {"metadata_version": "-1"}, - "'-1' is an invalid value for Metadata-Version. Error: Unknown Metadata" - " Version see" - " https://packaging.python.org/specifications/core-metadata", - ), - # name errors. - ( - {"metadata_version": "1.2"}, - "'' is an invalid value for Name. Error: This field is required. see" - " https://packaging.python.org/specifications/core-metadata", - ), - ( - {"metadata_version": "1.2", "name": "foo-"}, - "'foo-' is an invalid value for Name. Error: Must start and end with a" - " letter or numeral and contain only ascii numeric and '.', '_' and" - " '-'. see https://packaging.python.org/specifications/core-metadata", - ), - # version errors. - ( - {"metadata_version": "1.2", "name": "example"}, - "'' is an invalid value for Version. Error: This field is required. see" - " https://packaging.python.org/specifications/core-metadata", - ), - ( - {"metadata_version": "1.2", "name": "example", "version": "dog"}, - "'dog' is an invalid value for Version. Error: Must start and end with" - " a letter or numeral and contain only ascii numeric and '.', '_' and" - " '-'. see https://packaging.python.org/specifications/core-metadata", - ), - ], - ) - def test_fails_invalid_post_data( - self, pyramid_config, db_request, post_data, message - ): - pyramid_config.testing_securitypolicy(userid=1) - db_request.POST = MultiDict(post_data) - - -def foo(list_a, list_b): - results = ( - User.query.filter(User.foo == "bar") - .filter( # Because foo. - db.or_(User.field_a.astext.in_(list_a), User.field_b.astext.in_(list_b)) - ) - .filter(User.xyz.is_(None)) - # Another comment about the filtering on is_quux goes here. - .filter(db.not_(User.is_pending.astext.cast(db.Boolean).is_(True))) - .order_by(User.created_at.desc()) - .with_for_update(key_share=True) - .all() - ) - return results - - -def foo2(list_a, list_b): - # Standalone comment reasonably placed. - return ( - User.query.filter(User.foo == "bar") - .filter( - db.or_(User.field_a.astext.in_(list_a), User.field_b.astext.in_(list_b)) - ) - .filter(User.xyz.is_(None)) - ) - - -def foo3(list_a, list_b): - return ( - # Standalone comment but weirdly placed. - User.query.filter(User.foo == "bar") - .filter( - db.or_(User.field_a.astext.in_(list_a), User.field_b.astext.in_(list_b)) - ) - .filter(User.xyz.is_(None)) - ) -``` - -## Black Differences - -```diff ---- Black -+++ Ruff -@@ -4,8 +4,6 @@ - from com.my_lovely_company.my_lovely_team.my_lovely_project.my_lovely_component import ( - MyLovelyCompanyTeamProjectComponent as component, # DRY - ) -- -- - class C: - @pytest.mark.parametrize( - ("post_data", "message"), -@@ -54,8 +52,6 @@ - ): - pyramid_config.testing_securitypolicy(userid=1) - db_request.POST = MultiDict(post_data) -- -- - def foo(list_a, list_b): - results = ( - User.query.filter(User.foo == "bar") -@@ -70,8 +66,6 @@ - .all() - ) - return results -- -- - def foo2(list_a, list_b): - # Standalone comment reasonably placed. - return ( -@@ -81,8 +75,6 @@ - ) - .filter(User.xyz.is_(None)) - ) -- -- - def foo3(list_a, list_b): - return ( - # Standalone comment but weirdly placed. -``` - -## Ruff Output - -```py -from com.my_lovely_company.my_lovely_team.my_lovely_project.my_lovely_component import ( - MyLovelyCompanyTeamProjectComponent, # NOT DRY -) -from com.my_lovely_company.my_lovely_team.my_lovely_project.my_lovely_component import ( - MyLovelyCompanyTeamProjectComponent as component, # DRY -) -class C: - @pytest.mark.parametrize( - ("post_data", "message"), - [ - # metadata_version errors. - ( - {}, - "None is an invalid value for Metadata-Version. Error: This field is" - " required. see" - " https://packaging.python.org/specifications/core-metadata", - ), - ( - {"metadata_version": "-1"}, - "'-1' is an invalid value for Metadata-Version. Error: Unknown Metadata" - " Version see" - " https://packaging.python.org/specifications/core-metadata", - ), - # name errors. - ( - {"metadata_version": "1.2"}, - "'' is an invalid value for Name. Error: This field is required. see" - " https://packaging.python.org/specifications/core-metadata", - ), - ( - {"metadata_version": "1.2", "name": "foo-"}, - "'foo-' is an invalid value for Name. Error: Must start and end with a" - " letter or numeral and contain only ascii numeric and '.', '_' and" - " '-'. see https://packaging.python.org/specifications/core-metadata", - ), - # version errors. - ( - {"metadata_version": "1.2", "name": "example"}, - "'' is an invalid value for Version. Error: This field is required. see" - " https://packaging.python.org/specifications/core-metadata", - ), - ( - {"metadata_version": "1.2", "name": "example", "version": "dog"}, - "'dog' is an invalid value for Version. Error: Must start and end with" - " a letter or numeral and contain only ascii numeric and '.', '_' and" - " '-'. see https://packaging.python.org/specifications/core-metadata", - ), - ], - ) - def test_fails_invalid_post_data( - self, pyramid_config, db_request, post_data, message - ): - pyramid_config.testing_securitypolicy(userid=1) - db_request.POST = MultiDict(post_data) -def foo(list_a, list_b): - results = ( - User.query.filter(User.foo == "bar") - .filter( # Because foo. - db.or_(User.field_a.astext.in_(list_a), User.field_b.astext.in_(list_b)) - ) - .filter(User.xyz.is_(None)) - # Another comment about the filtering on is_quux goes here. - .filter(db.not_(User.is_pending.astext.cast(db.Boolean).is_(True))) - .order_by(User.created_at.desc()) - .with_for_update(key_share=True) - .all() - ) - return results -def foo2(list_a, list_b): - # Standalone comment reasonably placed. - return ( - User.query.filter(User.foo == "bar") - .filter( - db.or_(User.field_a.astext.in_(list_a), User.field_b.astext.in_(list_b)) - ) - .filter(User.xyz.is_(None)) - ) -def foo3(list_a, list_b): - return ( - # Standalone comment but weirdly placed. - User.query.filter(User.foo == "bar") - .filter( - db.or_(User.field_a.astext.in_(list_a), User.field_b.astext.in_(list_b)) - ) - .filter(User.xyz.is_(None)) - ) -``` - -## Black Output - -```py -from com.my_lovely_company.my_lovely_team.my_lovely_project.my_lovely_component import ( - MyLovelyCompanyTeamProjectComponent, # NOT DRY -) -from com.my_lovely_company.my_lovely_team.my_lovely_project.my_lovely_component import ( - MyLovelyCompanyTeamProjectComponent as component, # DRY -) - - -class C: - @pytest.mark.parametrize( - ("post_data", "message"), - [ - # metadata_version errors. - ( - {}, - "None is an invalid value for Metadata-Version. Error: This field is" - " required. see" - " https://packaging.python.org/specifications/core-metadata", - ), - ( - {"metadata_version": "-1"}, - "'-1' is an invalid value for Metadata-Version. Error: Unknown Metadata" - " Version see" - " https://packaging.python.org/specifications/core-metadata", - ), - # name errors. - ( - {"metadata_version": "1.2"}, - "'' is an invalid value for Name. Error: This field is required. see" - " https://packaging.python.org/specifications/core-metadata", - ), - ( - {"metadata_version": "1.2", "name": "foo-"}, - "'foo-' is an invalid value for Name. Error: Must start and end with a" - " letter or numeral and contain only ascii numeric and '.', '_' and" - " '-'. see https://packaging.python.org/specifications/core-metadata", - ), - # version errors. - ( - {"metadata_version": "1.2", "name": "example"}, - "'' is an invalid value for Version. Error: This field is required. see" - " https://packaging.python.org/specifications/core-metadata", - ), - ( - {"metadata_version": "1.2", "name": "example", "version": "dog"}, - "'dog' is an invalid value for Version. Error: Must start and end with" - " a letter or numeral and contain only ascii numeric and '.', '_' and" - " '-'. see https://packaging.python.org/specifications/core-metadata", - ), - ], - ) - def test_fails_invalid_post_data( - self, pyramid_config, db_request, post_data, message - ): - pyramid_config.testing_securitypolicy(userid=1) - db_request.POST = MultiDict(post_data) - - -def foo(list_a, list_b): - results = ( - User.query.filter(User.foo == "bar") - .filter( # Because foo. - db.or_(User.field_a.astext.in_(list_a), User.field_b.astext.in_(list_b)) - ) - .filter(User.xyz.is_(None)) - # Another comment about the filtering on is_quux goes here. - .filter(db.not_(User.is_pending.astext.cast(db.Boolean).is_(True))) - .order_by(User.created_at.desc()) - .with_for_update(key_share=True) - .all() - ) - return results - - -def foo2(list_a, list_b): - # Standalone comment reasonably placed. - return ( - User.query.filter(User.foo == "bar") - .filter( - db.or_(User.field_a.astext.in_(list_a), User.field_b.astext.in_(list_b)) - ) - .filter(User.xyz.is_(None)) - ) - - -def foo3(list_a, list_b): - return ( - # Standalone comment but weirdly placed. - User.query.filter(User.foo == "bar") - .filter( - db.or_(User.field_a.astext.in_(list_a), User.field_b.astext.in_(list_b)) - ) - .filter(User.xyz.is_(None)) - ) -``` - - diff --git a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__comments5_py.snap b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__comments5_py.snap index 7087a8c7112faf..38b091a219530e 100644 --- a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__comments5_py.snap +++ b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__comments5_py.snap @@ -86,75 +86,35 @@ if __name__ == "__main__": ```diff --- Black +++ Ruff -@@ -1,11 +1,6 @@ +@@ -1,11 +1,7 @@ while True: if something.changed: - do.stuff() # trailing comment - # Comment belongs to the `if` block. - # This one belongs to the `while` block. -- ++ do.stuff() + - # Should this one, too? I guess so. - -+ do.stuff() # This one is properly standalone now. for i in range(100): -@@ -15,27 +10,18 @@ +@@ -15,7 +11,6 @@ # then we do this print(i) - # and finally we loop around -- + with open(some_temp_file) as f: data = f.read() -- - try: - with open(some_other_file) as w: - w.write(data) - - except OSError: - print("problems") -- - import sys -- -- +@@ -33,7 +28,6 @@ # leading function comment def wat(): ... - # trailing function comment -- -- - # SECTION COMMENT -@@ -47,8 +33,6 @@ - @deco3 - def decorated1(): - ... -- -- - # leading 1 - @deco1 - # leading 2 -@@ -56,18 +40,12 @@ - # leading function comment - def decorated1(): - ... -- -- - # Note: this is fixed in - # Preview.empty_lines_before_class_or_def_with_leading_comments. - # In the current style, the user will have to split those lines by hand. - some_instruction -- -- - # This comment should be split from `some_instruction` by two lines but isn't. - def g(): - ... -- -- - if __name__ == "__main__": - main() + # SECTION COMMENT ``` ## Ruff Output @@ -163,6 +123,7 @@ if __name__ == "__main__": while True: if something.changed: do.stuff() + # This one is properly standalone now. for i in range(100): @@ -172,18 +133,25 @@ for i in range(100): # then we do this print(i) + with open(some_temp_file) as f: data = f.read() + try: with open(some_other_file) as w: w.write(data) except OSError: print("problems") + import sys + + # leading function comment def wat(): ... + + # SECTION COMMENT @@ -195,6 +163,8 @@ def wat(): @deco3 def decorated1(): ... + + # leading 1 @deco1 # leading 2 @@ -202,13 +172,19 @@ def decorated1(): # leading function comment def decorated1(): ... + + # Note: this is fixed in # Preview.empty_lines_before_class_or_def_with_leading_comments. # In the current style, the user will have to split those lines by hand. some_instruction + + # This comment should be split from `some_instruction` by two lines but isn't. def g(): ... + + if __name__ == "__main__": main() ``` diff --git a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__comments6_py.snap b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__comments6_py.snap index 6181d6489b6be3..d0727290f29263 100644 --- a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__comments6_py.snap +++ b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__comments6_py.snap @@ -131,100 +131,35 @@ aaaaaaaaaaaaa, bbbbbbbbb = map(list, map(itertools.chain.from_iterable, zip(*ite ```diff --- Black +++ Ruff -@@ -1,18 +1,12 @@ - from typing import Any, Tuple -- -- - def f( - a, # type: int - ): - pass -- -- - # test type comments - def f(a, b, c, d, e, f, g, h, i): - # type: (int, int, int, int, int, int, int, int, int) -> None - pass -- -- - def f( - a, # type: int - b, # type: int -@@ -26,8 +20,6 @@ - ): - # type: (...) -> None - pass -- -- - def f( - arg, # type: int - *args, # type: *Any -@@ -36,8 +28,6 @@ - ): - # type: (...) -> None - pass -- -- - def f( - a, # type: int - b, # type: int -@@ -66,23 +56,17 @@ +@@ -66,7 +66,7 @@ + element + another_element + another_element_with_long_name - ) # type: int -- -- + ) + + def f( - x, # not a type comment - y, # type: int - ): - # type: (...) -> None - pass -- -- - def f( - x, # not a type comment - ): # type: (int) -> None - pass -- -- - def func( - a=some_list[0], # type: int - ): # type: () -> int -@@ -102,17 +86,12 @@ - c = call( - "aaaaaaaa", "aaaaaaaa", "aaaaaaaa", "aaaaaaaa", "aaaaaaaa", "aaaaaaaa", "aaaaaaaa" # type: ignore - ) -- -- - result = ( # aaa - "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" - ) -- - AAAAAAAAAAAAA = [AAAAAAAAAAAAA] + SHARED_AAAAAAAAAAAAA + USER_AAAAAAAAAAAAA + AAAAAAAAAAAAA # type: ignore -- - call_to_some_function_asdf( - foo, - [AAAAAAAAAAAAAAAAAAAAAAA, AAAAAAAAAAAAAAAAAAAAAAA, AAAAAAAAAAAAAAAAAAAAAAA, BBBBBBBBBBBB], # type: ignore - ) -- - aaaaaaaaaaaaa, bbbbbbbbb = map(list, map(itertools.chain.from_iterable, zip(*items))) # type: ignore[arg-type] ``` ## Ruff Output ```py from typing import Any, Tuple + + def f( a, # type: int ): pass + + # test type comments def f(a, b, c, d, e, f, g, h, i): # type: (int, int, int, int, int, int, int, int, int) -> None pass + + def f( a, # type: int b, # type: int @@ -238,6 +173,8 @@ def f( ): # type: (...) -> None pass + + def f( arg, # type: int *args, # type: *Any @@ -246,6 +183,8 @@ def f( ): # type: (...) -> None pass + + def f( a, # type: int b, # type: int @@ -275,16 +214,22 @@ def f( + another_element + another_element_with_long_name ) + + def f( x, # not a type comment y, # type: int ): # type: (...) -> None pass + + def f( x, # not a type comment ): # type: (int) -> None pass + + def func( a=some_list[0], # type: int ): # type: () -> int @@ -304,14 +249,19 @@ def func( c = call( "aaaaaaaa", "aaaaaaaa", "aaaaaaaa", "aaaaaaaa", "aaaaaaaa", "aaaaaaaa", "aaaaaaaa" # type: ignore ) + + result = ( # aaa "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" ) + AAAAAAAAAAAAA = [AAAAAAAAAAAAA] + SHARED_AAAAAAAAAAAAA + USER_AAAAAAAAAAAAA + AAAAAAAAAAAAA # type: ignore + call_to_some_function_asdf( foo, [AAAAAAAAAAAAAAAAAAAAAAA, AAAAAAAAAAAAAAAAAAAAAAA, AAAAAAAAAAAAAAAAAAAAAAA, BBBBBBBBBBBB], # type: ignore ) + aaaaaaaaaaaaa, bbbbbbbbb = map(list, map(itertools.chain.from_iterable, zip(*items))) # type: ignore[arg-type] ``` diff --git a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__comments9_py.snap b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__comments9_py.snap index adc746764245d0..97ea9a42fb1c17 100644 --- a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__comments9_py.snap +++ b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__comments9_py.snap @@ -152,99 +152,19 @@ def bar(): ```diff --- Black +++ Ruff -@@ -1,60 +1,35 @@ - # Test for https://github.com/psf/black/issues/246. +@@ -35,9 +35,10 @@ + some = statement -- -- - # This comment should be split from the statement above by two lines. - def function(): - pass -- -- - some = statement -- -- - # This multiline comments section - # should be split from the statement - # above by two lines. - def function(): - pass -- -- - some = statement -- -- - # This comment should be split from the statement above by two lines. - async def async_function(): - pass -- -- - some = statement -- -- - # This comment should be split from the statement above by two lines. - class MyClass: - pass -- -- - some = statement - # This should be stick to the statement above +-# This should be stick to the statement above -- + ++# This should be stick to the statement above ++ # This should be split from the above by two lines class MyClassWithComplexLeadingComments: pass -- -- - class ClassWithDocstring: - """A docstring.""" -- -- - # Leading comment after a class with just a docstring - class MyClassAfterAnotherClassWithDocstring: - pass -- -- - some = statement -- -- - # leading 1 - @deco1 - # leading 2 -@@ -65,11 +40,7 @@ - # leading 4 - def decorated(): - pass -- -- - some = statement -- -- - # leading 1 - @deco1 - # leading 2 -@@ -80,11 +51,7 @@ - # leading 4 - def decorated_with_split_leading_comments(): - pass -- -- - some = statement -- -- - # leading 1 - @deco1 - # leading 2 -@@ -95,66 +62,44 @@ - # leading 4 that already has an empty line - def decorated_with_split_leading_comments(): - pass -- -- - def main(): - if a: +@@ -102,11 +103,9 @@ # Leading comment before inline function def inline(): pass @@ -256,10 +176,7 @@ def bar(): else: # More leading comments def inline_after_else(): - pass -- -- - if a: +@@ -117,11 +116,9 @@ # Leading comment before "top-level inline" function def top_level_quote_inline(): pass @@ -271,39 +188,24 @@ def bar(): else: # More leading comments def top_level_quote_inline_after_else(): - pass -- -- - class MyClass: - # First method has no empty lines between bare class def. - # More comments. - def first_method(self): - pass -- -- +@@ -138,7 +135,6 @@ # Regression test for https://github.com/psf/black/issues/3454. def foo(): pass - # Trailing comment that belongs to this function -- -- + + @decorator1 - @decorator2 # fmt: skip - def bar(): - pass -- -- +@@ -150,9 +146,6 @@ # Regression test for https://github.com/psf/black/issues/3454. def foo(): pass - # Trailing comment that belongs to this function. - # NOTE this comment only has one empty line below, and the formatter - # should enforce two blank lines. -- -- + + @decorator1 - # A standalone comment - def bar(): ``` ## Ruff Output @@ -312,35 +214,61 @@ def bar(): # Test for https://github.com/psf/black/issues/246. some = statement + + # This comment should be split from the statement above by two lines. def function(): pass + + some = statement + + # This multiline comments section # should be split from the statement # above by two lines. def function(): pass + + some = statement + + # This comment should be split from the statement above by two lines. async def async_function(): pass + + some = statement + + # This comment should be split from the statement above by two lines. class MyClass: pass + + some = statement + + # This should be stick to the statement above # This should be split from the above by two lines class MyClassWithComplexLeadingComments: pass + + class ClassWithDocstring: """A docstring.""" + + # Leading comment after a class with just a docstring class MyClassAfterAnotherClassWithDocstring: pass + + some = statement + + # leading 1 @deco1 # leading 2 @@ -351,7 +279,11 @@ some = statement # leading 4 def decorated(): pass + + some = statement + + # leading 1 @deco1 # leading 2 @@ -362,7 +294,11 @@ some = statement # leading 4 def decorated_with_split_leading_comments(): pass + + some = statement + + # leading 1 @deco1 # leading 2 @@ -373,6 +309,8 @@ some = statement # leading 4 that already has an empty line def decorated_with_split_leading_comments(): pass + + def main(): if a: # Leading comment before inline function @@ -385,6 +323,8 @@ def main(): # More leading comments def inline_after_else(): pass + + if a: # Leading comment before "top-level inline" function def top_level_quote_inline(): @@ -396,21 +336,31 @@ else: # More leading comments def top_level_quote_inline_after_else(): pass + + class MyClass: # First method has no empty lines between bare class def. # More comments. def first_method(self): pass + + # Regression test for https://github.com/psf/black/issues/3454. def foo(): pass + + @decorator1 @decorator2 # fmt: skip def bar(): pass + + # Regression test for https://github.com/psf/black/issues/3454. def foo(): pass + + @decorator1 # A standalone comment def bar(): diff --git a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__comments_non_breaking_space_py.snap b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__comments_non_breaking_space_py.snap index 306cbb3e56d5d5..3709a25f6582b1 100644 --- a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__comments_non_breaking_space_py.snap +++ b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__comments_non_breaking_space_py.snap @@ -32,7 +32,7 @@ def function(a:int=42): ```diff --- Black +++ Ruff -@@ -1,23 +1,16 @@ +@@ -1,23 +1,20 @@ -from .config import ( - ConfigTypeAttributes, - Int, @@ -41,16 +41,16 @@ def function(a:int=42): +from .config import ( ConfigTypeAttributes, Int, Path, # String, + # DEFAULT_TYPE_ATTRIBUTES, ) -- + result = 1 # A simple comment -result = (1,) # Another one -- +result = ( 1, ) # Another one + result = 1 #  type: ignore result = 1 # This comment is talking about type: ignore square = Square(4) #  type: Optional[Square] -- -- + + -def function(a: int = 42): - """This docstring is already formatted - a @@ -72,11 +72,15 @@ def function(a:int=42): from .config import ( ConfigTypeAttributes, Int, Path, # String, # DEFAULT_TYPE_ATTRIBUTES, ) + result = 1 # A simple comment result = ( 1, ) # Another one + result = 1 #  type: ignore result = 1 # This comment is talking about type: ignore square = Square(4) #  type: Optional[Square] + + def function(a:int=42): """ This docstring is already formatted a diff --git a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__comments_py.snap b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__comments_py.snap index 419cf8868bd3a5..12a415a0577f49 100644 --- a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__comments_py.snap +++ b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__comments_py.snap @@ -109,18 +109,7 @@ async def wat(): ```diff --- Black +++ Ruff -@@ -8,27 +8,17 @@ - - Possibly also many, many lines. - """ -- - import os.path - import sys -- - import a - from b.c import X # some noqa comment -- - try: +@@ -19,14 +19,9 @@ import fast except ImportError: import slow as fast @@ -132,36 +121,12 @@ async def wat(): - # some strings - y # type: ignore -) -- -- +# some strings +y # type: ignore - def function(default=None): - """Docstring comes first. -@@ -45,12 +35,8 @@ - # This return is also commented for some reason. - return default -- -- - # Explains why we use global state. - GLOBAL_STATE = {"a": a(1), "b": a(2), "c": a(3)} -- -- - # Another comment! - # This time two lines. - -@@ -73,8 +59,6 @@ - - self.spam = 4 - """Docstring for instance attribute spam.""" -- -- - #'

This is pweave!

- - -@@ -93,4 +77,4 @@ + def function(default=None): +@@ -93,4 +88,4 @@ # Some closing comments. # Maybe Vim or Emacs directives for formatting. @@ -183,10 +148,13 @@ async def wat(): Possibly also many, many lines. """ + import os.path import sys + import a from b.c import X # some noqa comment + try: import fast except ImportError: @@ -194,6 +162,8 @@ except ImportError: y = 1 # some strings y # type: ignore + + def function(default=None): """Docstring comes first. @@ -210,8 +180,12 @@ def function(default=None): # This return is also commented for some reason. return default + + # Explains why we use global state. GLOBAL_STATE = {"a": a(1), "b": a(2), "c": a(3)} + + # Another comment! # This time two lines. @@ -234,6 +208,8 @@ class Foo: self.spam = 4 """Docstring for instance attribute spam.""" + + #'

This is pweave!

diff --git a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__docstring_preview_py.snap b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__docstring_preview_py.snap index 3a06521d115a6a..b95e94cf32ef00 100644 --- a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__docstring_preview_py.snap +++ b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__docstring_preview_py.snap @@ -63,57 +63,23 @@ def single_quote_docstring_over_line_limit2(): ```diff --- Black +++ Ruff -@@ -1,48 +1,32 @@ +@@ -1,9 +1,11 @@ def docstring_almost_at_line_limit(): - """long docstring.................................................................""" -- -- + """long docstring................................................................. + """ + + def docstring_almost_at_line_limit_with_prefix(): - f"""long docstring................................................................""" -- -- + f"""long docstring................................................................ + """ - def mulitline_docstring_almost_at_line_limit(): - """long docstring................................................................. - .................................................................................. - """ -- -- - def mulitline_docstring_almost_at_line_limit_with_prefix(): - f"""long docstring................................................................ - .................................................................................. - """ -- -- - def docstring_at_line_limit(): - """long docstring................................................................""" -- -- - def docstring_at_line_limit_with_prefix(): - f"""long docstring...............................................................""" -- -- - def multiline_docstring_at_line_limit(): - """first line----------------------------------------------------------------------- + def mulitline_docstring_almost_at_line_limit(): +@@ -45,4 +47,4 @@ - second line----------------------------------------------------------------------""" -- -- - def multiline_docstring_at_line_limit_with_prefix(): - f"""first line---------------------------------------------------------------------- - second line----------------------------------------------------------------------""" -- -- - def single_quote_docstring_over_line_limit(): - "We do not want to put the closing quote on a new line as that is invalid (see GH-3141)." -- -- def single_quote_docstring_over_line_limit2(): - "We do not want to put the closing quote on a new line as that is invalid (see GH-3141)." + 'We do not want to put the closing quote on a new line as that is invalid (see GH-3141).' @@ -125,33 +91,51 @@ def single_quote_docstring_over_line_limit2(): def docstring_almost_at_line_limit(): """long docstring................................................................. """ + + def docstring_almost_at_line_limit_with_prefix(): f"""long docstring................................................................ """ + + def mulitline_docstring_almost_at_line_limit(): """long docstring................................................................. .................................................................................. """ + + def mulitline_docstring_almost_at_line_limit_with_prefix(): f"""long docstring................................................................ .................................................................................. """ + + def docstring_at_line_limit(): """long docstring................................................................""" + + def docstring_at_line_limit_with_prefix(): f"""long docstring...............................................................""" + + def multiline_docstring_at_line_limit(): """first line----------------------------------------------------------------------- second line----------------------------------------------------------------------""" + + def multiline_docstring_at_line_limit_with_prefix(): f"""first line---------------------------------------------------------------------- second line----------------------------------------------------------------------""" + + def single_quote_docstring_over_line_limit(): "We do not want to put the closing quote on a new line as that is invalid (see GH-3141)." + + def single_quote_docstring_over_line_limit2(): 'We do not want to put the closing quote on a new line as that is invalid (see GH-3141).' ``` diff --git a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__docstring_py.snap b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__docstring_py.snap index 933f6529e7d1c8..58b5b5f29c3db9 100644 --- a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__docstring_py.snap +++ b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__docstring_py.snap @@ -234,7 +234,7 @@ def stable_quote_normalization_with_immediate_inner_single_quote(self): ```diff --- Black +++ Ruff -@@ -1,219 +1,157 @@ +@@ -1,83 +1,85 @@ class MyClass: + """ Multiline + class docstring @@ -251,64 +251,64 @@ def stable_quote_normalization_with_immediate_inner_single_quote(self): - method docstring - """ - pass -- -- + pass + + def foo(): - """This is a docstring with - some lines of text here - """ - return -- -- + """This is a docstring with + some lines of text here + """ + return + + def bar(): - """This is another docstring - with more lines of text - """ - return -- -- + '''This is another docstring + with more lines of text + ''' + return + + def baz(): - '''"This" is a string with some - embedded "quotes"''' - return -- -- + '''"This" is a string with some + embedded "quotes"''' + return + + def troz(): - """Indentation with tabs - is just as OK - """ - return -- -- + '''Indentation with tabs + is just as OK + ''' + return + + def zort(): - """Another - multiline - docstring - """ - pass -- -- + """Another + multiline + docstring + """ + pass + + def poit(): - """ - Lorem ipsum dolor sit amet. @@ -323,8 +323,6 @@ def stable_quote_normalization_with_immediate_inner_single_quote(self): - - aliquip ex ea commodo consequat - """ - pass -- -- + Consectetur adipiscing elit: + - sed do eiusmod tempor incididunt ut labore + - dolore magna aliqua @@ -333,16 +331,26 @@ def stable_quote_normalization_with_immediate_inner_single_quote(self): + - aliquip ex ea commodo consequat + """ + pass + + def under_indent(): - """ - These lines are indented in a way that does not - make sense. +- """ +- pass + """ + These lines are indented in a way that does not +make sense. + """ + pass -+def over_indent(): + + + 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 @@ -350,90 +358,78 @@ def stable_quote_normalization_with_immediate_inner_single_quote(self): """ - pass + pass -+def single_line(): -+ """But with a newline after it! -- --def over_indent(): -- """ -- This has a shallow indent -- - But some lines are deeper -- - And the closing quote is too deep - """ - pass -- -- --def single_line(): + + def single_line(): - """But with a newline after it!""" -- pass -- -- - def this(): - r""" - 'hey ho' - """ -- -- ++ """But with a newline after it! ++ ++ """ + pass + + +@@ -88,25 +90,30 @@ + + def that(): - """ "hey yah" """ -- -- + """ "hey yah" """ + + def and_that(): - """ - "hey yah" """ -- -- + """ + "hey yah" """ + + def and_this(): +- ''' +- "hey yah"''' + ''' + "hey yah"''' -+def multiline_whitespace(): + + + def multiline_whitespace(): +- """ """ + ''' + + + + - ''' -- "hey yah"''' -- -- --def multiline_whitespace(): -- """ """ -- -- ++ ''' + + def oneline_whitespace(): - """ """ -- -- + ''' ''' + + def empty(): - """""" -- -- +@@ -114,12 +121,11 @@ + + def single_quotes(): - "testing" -- -- ++ 'testing' + + -def believe_it_or_not_this_is_in_the_py_stdlib(): - ''' - "hey yah"''' -- -- -+ 'testing' +def believe_it_or_not_this_is_in_the_py_stdlib(): ''' +"hey yah"''' + + def ignored_docstring(): - """a => \ - b""" -- -- +@@ -128,32 +134,32 @@ + + def single_line_docstring_with_whitespace(): - """This should be stripped""" -- -- + """ This should be stripped """ + + def docstring_with_inline_tabs_and_space_indentation(): """hey @@ -449,8 +445,8 @@ def stable_quote_normalization_with_immediate_inner_single_quote(self): + + line ends with some tabs """ -- -- + + def docstring_with_inline_tabs_and_tab_indentation(): - """hey + """hey @@ -463,8 +459,6 @@ def stable_quote_normalization_with_immediate_inner_single_quote(self): - line ends with some tabs - """ - pass -- -- + tab separated value + tab at start of line and then a tab separated value + multiple tabs at the beginning and inline @@ -473,69 +467,51 @@ def stable_quote_normalization_with_immediate_inner_single_quote(self): + line ends with some tabs + """ + pass + + def backslash_space(): - """\ """ -- -- +@@ -161,14 +167,14 @@ + + def multiline_backslash_1(): - """ + ''' hey\there\ - \ """ -- -- + \ ''' + + def multiline_backslash_2(): - """ - hey there \ """ -- -- + ''' + hey there \ ''' + + # Regression test for #3425 - def multiline_backslash_really_long_dont_crash(): - """ - hey there hello guten tag hi hoow are you ola zdravstvuyte ciao como estas ca va \ """ -- -- +@@ -178,8 +184,8 @@ + + def multiline_backslash_3(): - """ - already escaped \\""" -- -- + ''' + already escaped \\ ''' + + def my_god_its_full_of_stars_1(): - "I'm sorry Dave\u2001" -- -- +@@ -188,7 +194,7 @@ + # the space below is actually a \u2001, removed in output def my_god_its_full_of_stars_2(): - "I'm sorry Dave" -- -- + "I'm sorry Dave " + + def docstring_almost_at_line_limit(): - """long docstring.................................................................""" -- -- - def docstring_almost_at_line_limit2(): - """long docstring................................................................. +@@ -213,7 +219,7 @@ - .................................................................................. - """ -- -- - def docstring_at_line_limit(): - """long docstring................................................................""" -- -- - def multiline_docstring_at_line_limit(): - """first line----------------------------------------------------------------------- - second line----------------------------------------------------------------------""" -- -- def stable_quote_normalization_with_immediate_inner_single_quote(self): - """' + '''' @@ -558,31 +534,43 @@ class MyClass: method docstring """ pass + + def foo(): """This is a docstring with some lines of text here """ return + + def bar(): '''This is another docstring with more lines of text ''' return + + def baz(): '''"This" is a string with some embedded "quotes"''' return + + def troz(): '''Indentation with tabs is just as OK ''' return + + def zort(): """Another multiline docstring """ pass + + def poit(): """ Lorem ipsum dolor sit amet. @@ -595,12 +583,16 @@ def poit(): - 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 @@ -608,23 +600,35 @@ def over_indent(): - 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 multiline_whitespace(): ''' @@ -632,19 +636,33 @@ def multiline_whitespace(): ''' + + def oneline_whitespace(): ''' ''' + + def empty(): """""" + + def single_quotes(): 'testing' + + def believe_it_or_not_this_is_in_the_py_stdlib(): ''' "hey yah"''' + + def ignored_docstring(): """a => \ b""" + + def single_line_docstring_with_whitespace(): """ This should be stripped """ + + def docstring_with_inline_tabs_and_space_indentation(): """hey @@ -655,6 +673,8 @@ def docstring_with_inline_tabs_and_space_indentation(): line ends with some tabs """ + + def docstring_with_inline_tabs_and_tab_indentation(): """hey @@ -666,40 +686,64 @@ def docstring_with_inline_tabs_and_tab_indentation(): line ends with some tabs """ pass + + def backslash_space(): """\ """ + + def multiline_backslash_1(): ''' hey\there\ \ ''' + + def multiline_backslash_2(): ''' hey there \ ''' + + # Regression test for #3425 def multiline_backslash_really_long_dont_crash(): """ hey there hello guten tag hi hoow are you ola zdravstvuyte ciao como estas ca va \ """ + + def multiline_backslash_3(): ''' already escaped \\ ''' + + def my_god_its_full_of_stars_1(): "I'm sorry Dave\u2001" + + # the space below is actually a \u2001, removed in output def my_god_its_full_of_stars_2(): "I'm sorry Dave " + + def docstring_almost_at_line_limit(): """long docstring.................................................................""" + + def docstring_almost_at_line_limit2(): """long docstring................................................................. .................................................................................. """ + + def docstring_at_line_limit(): """long docstring................................................................""" + + def multiline_docstring_at_line_limit(): """first line----------------------------------------------------------------------- second line----------------------------------------------------------------------""" + + def stable_quote_normalization_with_immediate_inner_single_quote(self): '''' diff --git a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__empty_lines_py.snap b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__empty_lines_py.snap index 741cc1757f4c41..9782dc017148bc 100644 --- a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__empty_lines_py.snap +++ b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__empty_lines_py.snap @@ -105,10 +105,8 @@ def g(): ```diff --- Black +++ Ruff -@@ -1,11 +1,9 @@ - """Docstring.""" -- -- +@@ -3,9 +3,9 @@ + # leading comment def f(): - NO = "" @@ -120,7 +118,7 @@ def g(): t = leaf.type p = leaf.parent # trailing comment -@@ -16,14 +14,19 @@ +@@ -16,14 +16,19 @@ if t == token.COMMENT: # another trailing comment return DOUBLESPACE @@ -140,17 +138,12 @@ def g(): if prevp.type == token.EQUAL: if prevp.parent and prevp.parent.type in { syms.typedargslist, -@@ -43,17 +46,14 @@ - syms.dictsetmaker, - }: - return NO -- -- +@@ -48,12 +53,11 @@ ############################################################################### # SECTION BECAUSE SECTIONS ############################################################################### - - + def g(): - NO = "" - SPACE = " " @@ -161,7 +154,7 @@ def g(): t = leaf.type p = leaf.parent -@@ -67,7 +67,7 @@ +@@ -67,7 +71,7 @@ return DOUBLESPACE # Another comment because more comments @@ -176,6 +169,8 @@ def g(): ```py """Docstring.""" + + # leading comment def f(): NO = '' @@ -223,6 +218,8 @@ def f(): syms.dictsetmaker, }: return NO + + ############################################################################### # SECTION BECAUSE SECTIONS ############################################################################### diff --git a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__expression_py.snap b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__expression_py.snap index cf47dd1cbea380..4e3a341a693f2f 100644 --- a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__expression_py.snap +++ b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__expression_py.snap @@ -511,26 +511,22 @@ last_call() Ø = set() authors.łukasz.say_thanks() mapping = { -@@ -233,138 +170,83 @@ - C: 0.1 * (10.0 / 12), - D: 0.1 * (10.0 / 12), - } -- -- +@@ -237,134 +174,85 @@ + def gen(): yield from outside_of_generator - a = yield - b = yield - c = yield -- -- + a = (yield) + b = ((yield)) + c = (((yield))) + + async def f(): await some.complicated[0].call(with_args=(True or (1 is not 1))) -- -- + + -print(*[] or [1]) +print(* [] or [1]) print(**{1: 3} if False else {x: x for x in range(3)}) @@ -861,13 +857,19 @@ mapping = { C: 0.1 * (10.0 / 12), D: 0.1 * (10.0 / 12), } + + def gen(): yield from outside_of_generator a = (yield) b = ((yield)) c = (((yield))) + + async def f(): await some.complicated[0].call(with_args=(True or (1 is not 1))) + + print(* [] or [1]) print(**{1: 3} if False else {x: x for x in range(3)}) print(* lambda x: x) diff --git a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__fmtonoff2_py.snap b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__fmtonoff2_py.snap index b7f2c2732c4d63..33388de664852c 100644 --- a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__fmtonoff2_py.snap +++ b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__fmtonoff2_py.snap @@ -53,32 +53,34 @@ def test_calculate_fades(): ```diff --- Black +++ Ruff -@@ -1,8 +1,6 @@ - import pytest -- +@@ -3,6 +3,7 @@ TmSt = 1 TmEx = 2 -- + ++ # fmt: off # Test data: -@@ -17,19 +15,15 @@ - ]) +@@ -18,18 +19,22 @@ def test_fader(test): pass -- + ++ def check_fader(test): pass -- + ++ def verify_fader(test): # misaligned comment pass -- + ++ def verify_fader(test): """Hey, ho.""" assert test.passed() -- + ++ def test_calculate_fades(): calcs = [ # one is zero/none @@ -88,8 +90,11 @@ def test_calculate_fades(): ```py import pytest + TmSt = 1 TmEx = 2 + + # fmt: off # Test data: @@ -104,15 +109,23 @@ TmEx = 2 ]) def test_fader(test): pass + + def check_fader(test): pass + + def verify_fader(test): # misaligned comment pass + + def verify_fader(test): """Hey, ho.""" assert test.passed() + + def test_calculate_fades(): calcs = [ # one is zero/none diff --git a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__fmtonoff3_py.snap b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__fmtonoff3_py.snap index 772a2828adf674..a092c47a2aa433 100644 --- a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__fmtonoff3_py.snap +++ b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__fmtonoff3_py.snap @@ -30,8 +30,11 @@ x = [ ```diff --- Black +++ Ruff -@@ -12,4 +12,6 @@ +@@ -10,6 +10,9 @@ + 1, 2, + 3, 4, ] ++ # fmt: on -x = [1, 2, 3, 4] @@ -55,6 +58,7 @@ x = [ 1, 2, 3, 4, ] + # fmt: on x = [ diff --git a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__fmtonoff4_py.snap b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__fmtonoff4_py.snap index 6f145776200c0d..4c768c3d7d8dec 100644 --- a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__fmtonoff4_py.snap +++ b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__fmtonoff4_py.snap @@ -26,14 +26,15 @@ def f(): pass ```diff --- Black +++ Ruff -@@ -4,17 +4,9 @@ +@@ -4,17 +4,11 @@ 3, 4, ]) # fmt: on -def f(): - pass -- -- ++def f(): pass + + -@test( - [ - 1, @@ -44,7 +45,6 @@ def f(): pass -) -def f(): - pass -+def f(): pass +@test([ + 1, 2, + 3, 4, @@ -62,6 +62,8 @@ def f(): pass ]) # fmt: on def f(): pass + + @test([ 1, 2, 3, 4, diff --git a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__fmtonoff5_py.snap b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__fmtonoff5_py.snap index cab9d6960c7fd8..db5263f639e223 100644 --- a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__fmtonoff5_py.snap +++ b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__fmtonoff5_py.snap @@ -106,60 +106,37 @@ elif unformatted: # Regression test for https://github.com/psf/black/issues/2015. run( # fmt: off -@@ -22,8 +20,6 @@ - + path, - check=True, - ) -- -- - # Regression test for https://github.com/psf/black/issues/3026. - def test_func(): - # yapf: disable -@@ -34,8 +30,6 @@ - return True - - return False -- -- - # Regression test for https://github.com/psf/black/issues/2567. - if True: - # fmt: off -@@ -44,9 +38,7 @@ +@@ -44,7 +42,7 @@ print ( "This won't be formatted" ) print ( "This won't be formatted either" ) else: - print("This will be formatted") -- -- + print ( "This will be formatted" ) + + # Regression test for https://github.com/psf/black/issues/3184. - class A: - async def call(param): -@@ -61,27 +53,18 @@ +@@ -61,7 +59,7 @@ elif param[0:4] in ("ZZZZ",): print ( "This won't be formatted either" ) - print("This will be formatted") -- -- + print ( "This will be formatted" ) + + # Regression test for https://github.com/psf/black/issues/2985. - class Named(t.Protocol): - # fmt: off - @property - def this_wont_be_formatted ( self ) -> str: ... -- -- +@@ -72,10 +70,7 @@ + + class Factory(t.Protocol): - def this_will_be_formatted(self, **kwargs) -> Named: - ... - - # fmt: on -- -- + def this_will_be_formatted ( self, **kwargs ) -> Named: ... + + # Regression test for https://github.com/psf/black/issues/3436. - if x: +@@ -83,5 +78,5 @@ return x # fmt: off elif unformatted: @@ -194,6 +171,8 @@ run( + path, check=True, ) + + # Regression test for https://github.com/psf/black/issues/3026. def test_func(): # yapf: disable @@ -204,6 +183,8 @@ def test_func(): return True return False + + # Regression test for https://github.com/psf/black/issues/2567. if True: # fmt: off @@ -213,6 +194,8 @@ if True: print ( "This won't be formatted either" ) else: print ( "This will be formatted" ) + + # Regression test for https://github.com/psf/black/issues/3184. class A: async def call(param): @@ -228,13 +211,19 @@ class A: print ( "This won't be formatted either" ) print ( "This will be formatted" ) + + # Regression test for https://github.com/psf/black/issues/2985. class Named(t.Protocol): # fmt: off @property def this_wont_be_formatted ( self ) -> str: ... + + class Factory(t.Protocol): def this_will_be_formatted ( self, **kwargs ) -> Named: ... + + # Regression test for https://github.com/psf/black/issues/3436. if x: return x diff --git a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__fmtonoff_py.snap b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__fmtonoff_py.snap index 1766ef2a6b406f..71c0fceef36d39 100644 --- a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__fmtonoff_py.snap +++ b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__fmtonoff_py.snap @@ -199,13 +199,10 @@ d={'a':1, ```diff --- Black +++ Ruff -@@ -1,20 +1,17 @@ - #!/usr/bin/env python3 - import asyncio - import sys -- +@@ -4,17 +4,18 @@ + from third_party import X, Y, Z -- + -from library import some_connection, some_decorator - +from library import some_connection, \ @@ -216,6 +213,8 @@ d={'a':1, # fmt: on -f"trigger 3.6 mode" +f'trigger 3.6 mode' ++ ++ # Comment 1 # Comment 2 @@ -223,15 +222,37 @@ d={'a':1, # fmt: off def func_no_args(): -@@ -39,72 +36,41 @@ +@@ -26,11 +27,15 @@ + continue + exec('new-style exec', {}, {}) + return None ++ ++ + async def coroutine(arg, exec=False): + 'Single-line docstring. Multiline is harder to reformat.' + async with some_connection() as conn: + await conn.do_what_i_mean('SELECT bobby, tables FROM xkcd', timeout=2) + await asyncio.sleep(1) ++ ++ + @asyncio.coroutine + @some_decorator( + with_args=True, +@@ -38,28 +43,19 @@ + ) def function_signature_stress_test(number:int,no_annotation=None,text:str='default',* ,debug:bool=False,**kwargs) -> str: return text[number:-1] ++ ++ # fmt: on -def spaces(a=1, b=(), c=[], d={}, e=True, f=-1, g=1 if False else 2, h="", i=r""): - offset = attr.ib(default=attr.Factory(lambda: _r.uniform(1, 2))) - assert task._cancel_stack[: len(old_stack)] == old_stack -- -- ++def spaces(a=1, b=(), c=[], d={}, e=True, f=-1, g=1 if False else 2, h="", i=r''): ++ offset = attr.ib(default=attr.Factory( lambda: _r.uniform(1, 2))) ++ assert task._cancel_stack[:len(old_stack)] == old_stack + + -def spaces_types( - a: int = 1, - b: tuple = (), @@ -244,53 +265,43 @@ d={'a':1, - i: str = 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)): - ... -- -- -+def spaces(a=1, b=(), c=[], d={}, e=True, f=-1, g=1 if False else 2, h="", i=r''): -+ offset = attr.ib(default=attr.Factory( lambda: _r.uniform(1, 2))) -+ assert task._cancel_stack[:len(old_stack)] == old_stack -+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)): + ... + + something = { - # fmt: off - key: 'value', - } -- -- - def subscriptlist(): - atom[ - # fmt: off +@@ -74,23 +70,20 @@ 'some big and', 'complex subscript', # fmt: on - goes + here, - andhere, - ] -- -- + goes + here, andhere, + ] + + def import_as_names(): # fmt: off from hello import a, b 'unformatted' - # fmt: on -- -- + + def testlist_star_expr(): # fmt: off a , b = *hello 'unformatted' - # fmt: on -- -- + + def yield_expr(): - # fmt: off +@@ -98,11 +91,10 @@ yield hello 'unformatted' # fmt: on @@ -300,22 +311,18 @@ d={'a':1, ( yield hello ) 'unformatted' - # fmt: on -- -- + + def example(session): - # fmt: off - result = session\ -@@ -113,9 +79,6 @@ +@@ -113,7 +105,6 @@ models.Customer.email == email_address)\ .order_by(models.Customer.id.asc())\ .all() - # fmt: on -- -- - def off_and_on_without_data(): - """All comments here are technically on the same prefix. -@@ -123,12 +86,12 @@ + + def off_and_on_without_data(): +@@ -123,8 +114,10 @@ """ # fmt: off @@ -326,12 +333,8 @@ d={'a':1, + # fmt: on pass -- -- - def on_and_off_broken(): - """Another known limitation.""" - # fmt: on -@@ -137,21 +100,10 @@ + +@@ -137,21 +130,12 @@ and_=indeed . it is not formatted because . the . handling . inside . generate_ignored_nodes() now . considers . multiple . fmt . directives . within . one . prefix @@ -339,8 +342,8 @@ d={'a':1, - # fmt: off - # ...but comments still get reformatted even though they should not be - # fmt: on -- -- + + def long_lines(): if True: typedargslist.extend( @@ -354,22 +357,18 @@ d={'a':1, ) # fmt: off a = ( -@@ -182,24 +134,19 @@ - re.MULTILINE|re.VERBOSE - # fmt: on - ) -- -- +@@ -186,20 +170,19 @@ + def single_literal_yapf_disable(): """Black does not support this.""" - BAZ = {(1, 2, 3, 4), (5, 6, 7, 8), (9, 10, 11, 12)} # yapf: disable -- -- + BAZ = { + (1, 2, 3, 4), + (5, 6, 7, 8), + (9, 10, 11, 12) + } + + cfg.rule( - "Default", - "address", @@ -388,7 +387,7 @@ d={'a':1, # fmt: off xxxxxxx_xxxxxxxxxxxx={ "xxxxxxxx": { -@@ -214,7 +161,7 @@ +@@ -214,7 +197,7 @@ }, }, # fmt: on @@ -405,7 +404,9 @@ d={'a':1, #!/usr/bin/env python3 import asyncio import sys + from third_party import X, Y, Z + from library import some_connection, \ some_decorator # fmt: off @@ -413,6 +414,8 @@ from third_party import (X, Y, Z) # fmt: on f'trigger 3.6 mode' + + # Comment 1 # Comment 2 @@ -427,11 +430,15 @@ def func_no_args(): continue exec('new-style exec', {}, {}) return None + + async def coroutine(arg, exec=False): 'Single-line docstring. Multiline is harder to reformat.' async with some_connection() as conn: await conn.do_what_i_mean('SELECT bobby, tables FROM xkcd', timeout=2) await asyncio.sleep(1) + + @asyncio.coroutine @some_decorator( with_args=True, @@ -439,17 +446,27 @@ many_args=[1,2,3] ) def function_signature_stress_test(number:int,no_annotation=None,text:str='default',* ,debug:bool=False,**kwargs) -> str: return text[number:-1] + + # fmt: on def spaces(a=1, b=(), c=[], d={}, e=True, f=-1, g=1 if False else 2, h="", i=r''): offset = attr.ib(default=attr.Factory( lambda: _r.uniform(1, 2))) assert task._cancel_stack[:len(old_stack)] == old_stack + + 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)): ... + + something = { # fmt: off key: 'value', } + + def subscriptlist(): atom[ # fmt: off @@ -458,14 +475,20 @@ def subscriptlist(): # fmt: on goes + here, andhere, ] + + def import_as_names(): # fmt: off from hello import a, b 'unformatted' + + def testlist_star_expr(): # fmt: off a , b = *hello 'unformatted' + + def yield_expr(): # fmt: off yield hello @@ -475,6 +498,8 @@ def yield_expr(): # fmt: off ( yield hello ) 'unformatted' + + def example(session): # fmt: off result = session\ @@ -483,6 +508,8 @@ def example(session): models.Customer.email == email_address)\ .order_by(models.Customer.id.asc())\ .all() + + def off_and_on_without_data(): """All comments here are technically on the same prefix. @@ -496,6 +523,8 @@ def off_and_on_without_data(): # fmt: on pass + + def on_and_off_broken(): """Another known limitation.""" # fmt: on @@ -504,6 +533,8 @@ def on_and_off_broken(): and_=indeed . it is not formatted because . the . handling . inside . generate_ignored_nodes() now . considers . multiple . fmt . directives . within . one . prefix + + def long_lines(): if True: typedargslist.extend( @@ -538,6 +569,8 @@ def long_lines(): re.MULTILINE|re.VERBOSE # fmt: on ) + + def single_literal_yapf_disable(): """Black does not support this.""" BAZ = { @@ -545,6 +578,8 @@ def single_literal_yapf_disable(): (5, 6, 7, 8), (9, 10, 11, 12) } + + cfg.rule( "Default", "address", xxxx_xxxx=["xxx-xxxxxx-xxxxxxxxxx"], diff --git a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__fmtskip8_py.snap b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__fmtskip8_py.snap index 358018b4e0f6bb..50961239a455af 100644 --- a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__fmtskip8_py.snap +++ b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__fmtskip8_py.snap @@ -75,65 +75,14 @@ async def test_async_with(): ```diff --- Black +++ Ruff -@@ -2,15 +2,10 @@ +@@ -2,7 +2,6 @@ def some_func( unformatted, args ): # fmt: skip print("I am some_func") return 0 - # Make sure this comment is not removed. -- -- + + # Make sure a leading comment is not removed. - async def some_async_func( unformatted, args): # fmt: skip - print("I am some_async_func") - await asyncio.sleep(1) -- -- - # Make sure a leading comment is not removed. - class SomeClass( Unformatted, SuperClasses ): # fmt: skip - def some_method( self, unformatted, args ): # fmt: skip -@@ -20,8 +15,6 @@ - async def some_async_method( self, unformatted, args ): # fmt: skip - print("I am some_async_method") - await asyncio.sleep(1) -- -- - # Make sure a leading comment is not removed. - if unformatted_call( args ): # fmt: skip - print("First branch") -@@ -30,33 +23,21 @@ - print("Second branch") - else : # fmt: skip - print("Last branch") -- -- - while some_condition( unformatted, args ): # fmt: skip - print("Do something") -- -- - for i in some_iter( unformatted, args ): # fmt: skip - print("Do something") -- -- - async def test_async_for(): - async for i in some_async_iter( unformatted, args ): # fmt: skip - print("Do something") -- -- - try : # fmt: skip - some_call() - except UnformattedError as ex: # fmt: skip - handle_exception() - finally : # fmt: skip - finally_call() -- -- - with give_me_context( unformatted, args ): # fmt: skip - print("Do something") -- -- - async def test_async_with(): - async with give_me_async_context( unformatted, args ): # fmt: skip - print("Do something") ``` ## Ruff Output @@ -143,10 +92,14 @@ async def test_async_with(): def some_func( unformatted, args ): # fmt: skip print("I am some_func") return 0 + + # Make sure a leading comment is not removed. async def some_async_func( unformatted, args): # fmt: skip print("I am some_async_func") await asyncio.sleep(1) + + # Make sure a leading comment is not removed. class SomeClass( Unformatted, SuperClasses ): # fmt: skip def some_method( self, unformatted, args ): # fmt: skip @@ -156,6 +109,8 @@ class SomeClass( Unformatted, SuperClasses ): # fmt: skip async def some_async_method( self, unformatted, args ): # fmt: skip print("I am some_async_method") await asyncio.sleep(1) + + # Make sure a leading comment is not removed. if unformatted_call( args ): # fmt: skip print("First branch") @@ -164,21 +119,33 @@ elif another_unformatted_call( args ): # fmt: skip print("Second branch") else : # fmt: skip print("Last branch") + + while some_condition( unformatted, args ): # fmt: skip print("Do something") + + for i in some_iter( unformatted, args ): # fmt: skip print("Do something") + + async def test_async_for(): async for i in some_async_iter( unformatted, args ): # fmt: skip print("Do something") + + try : # fmt: skip some_call() except UnformattedError as ex: # fmt: skip handle_exception() finally : # fmt: skip finally_call() + + with give_me_context( unformatted, args ): # fmt: skip print("Do something") + + async def test_async_with(): async with give_me_async_context( unformatted, args ): # fmt: skip print("Do something") diff --git a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__function2_py.snap b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__function2_py.snap index 6af0b38a4eb9ff..1a6c83f39e8aec 100644 --- a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__function2_py.snap +++ b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__function2_py.snap @@ -82,12 +82,8 @@ with hmm_but_this_should_get_two_preceding_newlines(): ) limited.append(-limited.pop()) # negate top return A( -@@ -13,34 +13,22 @@ - very_long_argument_name2=-very.long.value.for_the_argument, - **kwargs, - ) -- -- +@@ -17,30 +17,24 @@ + def g(): "Docstring." - @@ -95,15 +91,15 @@ with hmm_but_this_should_get_two_preceding_newlines(): pass - print("Inner defs should breathe a little.") -- -- + + def h(): def inner(): pass - print("Inner defs should breathe a little.") -- -- + + if os.name == "posix": import termios - @@ -117,7 +113,7 @@ with hmm_but_this_should_get_two_preceding_newlines(): def i_should_be_followed_by_only_one_newline(): pass -@@ -54,12 +42,9 @@ +@@ -54,12 +48,10 @@ class IHopeYouAreHavingALovelyDay: def __call__(self): print("i_should_be_followed_by_only_one_newline") @@ -127,7 +123,7 @@ with hmm_but_this_should_get_two_preceding_newlines(): def foo(): pass - -- + with hmm_but_this_should_get_two_preceding_newlines(): pass ``` @@ -150,15 +146,21 @@ def f( very_long_argument_name2=-very.long.value.for_the_argument, **kwargs, ) + + def g(): "Docstring." def inner(): pass print("Inner defs should breathe a little.") + + def h(): def inner(): pass print("Inner defs should breathe a little.") + + if os.name == "posix": import termios def i_should_be_followed_by_only_one_newline(): @@ -183,6 +185,7 @@ else: def foo(): pass + with hmm_but_this_should_get_two_preceding_newlines(): pass ``` diff --git a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__function_py.snap b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__function_py.snap index a1ca74dcabfde7..ceeff81fdca855 100644 --- a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__function_py.snap +++ b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__function_py.snap @@ -108,21 +108,18 @@ def __await__(): return (yield) ```diff --- Black +++ Ruff -@@ -1,100 +1,52 @@ - #!/usr/bin/env python3 - import asyncio - import sys -- +@@ -4,97 +4,67 @@ + from third_party import X, Y, Z -- + -from library import some_connection, some_decorator -- --f"trigger 3.6 mode" -- -- +from library import some_connection, \ + some_decorator +f'trigger 3.6 mode' + +-f"trigger 3.6 mode" +- + def func_no_args(): - a - b @@ -136,8 +133,6 @@ def __await__(): return (yield) - continue - exec("new-style exec", {}, {}) - return None -- -- + a; b; c + if True: raise RuntimeError + if False: ... @@ -146,17 +141,19 @@ def __await__(): return (yield) + continue + exec("new-style exec", {}, {}) + return None + + async def coroutine(arg, exec=False): - "Single-line docstring. Multiline is harder to reformat." - async with some_connection() as conn: - await conn.do_what_i_mean("SELECT bobby, tables FROM xkcd", timeout=2) - await asyncio.sleep(1) -- -- + "Single-line docstring. Multiline is harder to reformat." + async with some_connection() as conn: + await conn.do_what_i_mean('SELECT bobby, tables FROM xkcd', timeout=2) + await asyncio.sleep(1) + + @asyncio.coroutine -@some_decorator(with_args=True, many_args=[1, 2, 3]) -def function_signature_stress_test( @@ -168,13 +165,22 @@ def __await__(): return (yield) - **kwargs, -) -> str: - return text[number:-1] -- -- ++@some_decorator( ++with_args=True, ++many_args=[1,2,3] ++) ++def function_signature_stress_test(number:int,no_annotation=None,text:str="default",* ,debug:bool=False,**kwargs) -> str: ++ return text[number:-1] + + -def spaces(a=1, b=(), c=[], d={}, e=True, f=-1, g=1 if False else 2, h="", i=r""): - offset = attr.ib(default=attr.Factory(lambda: _r.uniform(10000, 200000))) - assert task._cancel_stack[: len(old_stack)] == old_stack -- -- ++def spaces(a=1, b=(), c=[], d={}, e=True, f=-1, g=1 if False else 2, h="", i=r''): ++ offset = attr.ib(default=attr.Factory( lambda: _r.uniform(10000, 200000))) ++ assert task._cancel_stack[:len(old_stack)] == old_stack + + -def spaces_types( - a: int = 1, - b: tuple = (), @@ -187,24 +193,15 @@ def __await__(): return (yield) - i: str = 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) -- -- -+@some_decorator( -+with_args=True, -+many_args=[1,2,3] -+) -+def function_signature_stress_test(number:int,no_annotation=None,text:str="default",* ,debug:bool=False,**kwargs) -> str: -+ return text[number:-1] -+def spaces(a=1, b=(), c=[], d={}, e=True, f=-1, g=1 if False else 2, h="", i=r''): -+ offset = attr.ib(default=attr.Factory( lambda: _r.uniform(10000, 200000))) -+ assert task._cancel_stack[:len(old_stack)] == old_stack -+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) + + def example(session): - result = ( - session.query(models.Customer.id) @@ -215,14 +212,14 @@ def __await__(): return (yield) - .order_by(models.Customer.id.asc()) - .all() - ) -- -- + result = session.query(models.Customer.id).filter( + models.Customer.account_id == account_id, + models.Customer.email == email_address, + ).order_by( + models.Customer.id.asc() + ).all() + + def long_lines(): if True: typedargslist.extend( @@ -244,7 +241,7 @@ def __await__(): return (yield) # trailing standalone comment ) ) -@@ -117,23 +69,18 @@ +@@ -117,23 +87,22 @@ \n? ) $ @@ -252,8 +249,8 @@ def __await__(): return (yield) - re.MULTILINE | re.VERBOSE, + """, re.MULTILINE | re.VERBOSE ) -- -- + + def trailing_comma(): mapping = { - A: 0.25 * (10.0 / 12), @@ -261,13 +258,13 @@ def __await__(): return (yield) - C: 0.1 * (10.0 / 12), - D: 0.1 * (10.0 / 12), - } -- -- + A: 0.25 * (10.0 / 12), + B: 0.1 * (10.0 / 12), + C: 0.1 * (10.0 / 12), + D: 0.1 * (10.0 / 12), +} + + def f( - a, - **kwargs, @@ -276,12 +273,10 @@ def __await__(): return (yield) ) -> A: return ( yield from A( -@@ -142,7 +89,4 @@ - **kwargs, - ) +@@ -144,5 +113,4 @@ ) -- -- + + -def __await__(): - return (yield) +def __await__(): return (yield) @@ -293,10 +288,14 @@ def __await__(): return (yield) #!/usr/bin/env python3 import asyncio import sys + from third_party import X, Y, Z + from library import some_connection, \ some_decorator f'trigger 3.6 mode' + + def func_no_args(): a; b; c if True: raise RuntimeError @@ -306,11 +305,15 @@ def func_no_args(): continue exec("new-style exec", {}, {}) return None + + async def coroutine(arg, exec=False): "Single-line docstring. Multiline is harder to reformat." async with some_connection() as conn: await conn.do_what_i_mean('SELECT bobby, tables FROM xkcd', timeout=2) await asyncio.sleep(1) + + @asyncio.coroutine @some_decorator( with_args=True, @@ -318,12 +321,20 @@ many_args=[1,2,3] ) def function_signature_stress_test(number:int,no_annotation=None,text:str="default",* ,debug:bool=False,**kwargs) -> str: return text[number:-1] + + def spaces(a=1, b=(), c=[], d={}, e=True, f=-1, g=1 if False else 2, h="", i=r''): offset = attr.ib(default=attr.Factory( lambda: _r.uniform(10000, 200000))) assert task._cancel_stack[:len(old_stack)] == old_stack + + 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) + + def example(session): result = session.query(models.Customer.id).filter( models.Customer.account_id == account_id, @@ -331,6 +342,8 @@ def example(session): ).order_by( models.Customer.id.asc() ).all() + + def long_lines(): if True: typedargslist.extend( @@ -363,6 +376,8 @@ def long_lines(): $ """, re.MULTILINE | re.VERBOSE ) + + def trailing_comma(): mapping = { A: 0.25 * (10.0 / 12), @@ -370,6 +385,8 @@ def trailing_comma(): C: 0.1 * (10.0 / 12), D: 0.1 * (10.0 / 12), } + + def f( a, **kwargs, @@ -381,6 +398,8 @@ def f( **kwargs, ) ) + + def __await__(): return (yield) ``` diff --git a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__function_trailing_comma_py.snap b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__function_trailing_comma_py.snap index d5edb4eca18bea..6de2f2bfd16cb0 100644 --- a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__function_trailing_comma_py.snap +++ b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__function_trailing_comma_py.snap @@ -74,7 +74,7 @@ some_module.some_function( ```diff --- Black +++ Ruff -@@ -1,114 +1,46 @@ +@@ -1,69 +1,28 @@ -def f( - a, -): @@ -84,8 +84,8 @@ some_module.some_function( +def f(a,): + d = {'key': 'value',} tup = (1,) -- -- + + -def f2( - a, - b, @@ -98,8 +98,11 @@ some_module.some_function( - 1, - 2, - ) -- -- ++def f2(a,b,): ++ d = {'key': 'value', 'key2': 'value2',} ++ tup = (1,2,) + + -def f( - a: int = 1, -): @@ -111,9 +114,6 @@ some_module.some_function( - call2( - arg=[1, 2, 3], - ) -+def f2(a,b,): -+ d = {'key': 'value', 'key2': 'value2',} -+ tup = (1,2,) +def f(a:int=1,): + call(arg={'explode': 'this',}) + call2(arg=[1,2,3],) @@ -136,8 +136,8 @@ some_module.some_function( - ): + if a == {"a": 1,"b": 2,"c": 3,"d": 4,"e": 5,"f": 6,"g": 7,"h": 8,}["a"]: pass -- -- + + -def xxxxxxxxxxxxxxxxxxxxxxxxxxxx() -> ( - Set["xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"] -): @@ -150,20 +150,17 @@ some_module.some_function( - } - } - } -- -- +def xxxxxxxxxxxxxxxxxxxxxxxxxxxx() -> Set[ + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +]: + json = {"k": {"k2": {"k3": [1,]}}} + + # The type annotation shouldn't get a trailing comma since that would change its type. - # Relevant bug report: https://github.com/psf/black/issues/2381. - def some_function_with_a_really_long_name() -> ( - returning_a_deeply_nested_import_of_a_type_i_suppose - ): +@@ -74,24 +33,21 @@ pass -- -- + + -def some_method_with_a_really_long_name( - very_long_parameter_so_yeah: str, another_long_parameter: int -) -> another_case_of_returning_a_deeply_nested_import_of_a_type_i_suppose_cause_why_not: @@ -171,8 +168,8 @@ some_module.some_function( + another_case_of_returning_a_deeply_nested_import_of_a_type_i_suppose_cause_why_not +): pass -- -- + + def func() -> ( - also_super_long_type_annotation_that_may_cause_an_AST_related_crash_in_black( - this_shouldn_t_get_a_trailing_comma_too @@ -180,8 +177,8 @@ some_module.some_function( + also_super_long_type_annotation_that_may_cause_an_AST_related_crash_in_black(this_shouldn_t_get_a_trailing_comma_too) ): pass -- -- + + -def func() -> ( - also_super_long_type_annotation_that_may_cause_an_AST_related_crash_in_black( +def func() -> ((also_super_long_type_annotation_that_may_cause_an_AST_related_crash_in_black( @@ -190,9 +187,8 @@ some_module.some_function( + )) ): pass -- -- - # Make sure inner one-element tuple won't explode + +@@ -100,15 +56,7 @@ some_module.some_function( argument1, (one_element_tuple,), argument4, argument5, argument6 ) @@ -217,9 +213,13 @@ some_module.some_function( def f(a,): d = {'key': 'value',} tup = (1,) + + def f2(a,b,): d = {'key': 'value', 'key2': 'value2',} tup = (1,2,) + + def f(a:int=1,): call(arg={'explode': 'this',}) call2(arg=[1,2,3],) @@ -229,29 +229,41 @@ def f(a:int=1,): }["a"] if a == {"a": 1,"b": 2,"c": 3,"d": 4,"e": 5,"f": 6,"g": 7,"h": 8,}["a"]: pass + + def xxxxxxxxxxxxxxxxxxxxxxxxxxxx() -> Set[ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" ]: json = {"k": {"k2": {"k3": [1,]}}} + + # The type annotation shouldn't get a trailing comma since that would change its type. # Relevant bug report: https://github.com/psf/black/issues/2381. def some_function_with_a_really_long_name() -> ( returning_a_deeply_nested_import_of_a_type_i_suppose ): pass + + def some_method_with_a_really_long_name(very_long_parameter_so_yeah: str, another_long_parameter: int) -> ( another_case_of_returning_a_deeply_nested_import_of_a_type_i_suppose_cause_why_not ): pass + + def func() -> ( also_super_long_type_annotation_that_may_cause_an_AST_related_crash_in_black(this_shouldn_t_get_a_trailing_comma_too) ): pass + + def func() -> ((also_super_long_type_annotation_that_may_cause_an_AST_related_crash_in_black( this_shouldn_t_get_a_trailing_comma_too )) ): pass + + # Make sure inner one-element tuple won't explode some_module.some_function( argument1, (one_element_tuple,), argument4, argument5, argument6 diff --git a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__import_spacing_py.snap b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__import_spacing_py.snap index b7cde495e0c3ac..352abb25411fff 100644 --- a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__import_spacing_py.snap +++ b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__import_spacing_py.snap @@ -62,9 +62,8 @@ __all__ = ( ```diff --- Black +++ Ruff -@@ -1,55 +1,33 @@ - """The asyncio package, tracking PEP 3156.""" -- +@@ -2,12 +2,13 @@ + # flake8: noqa -from logging import WARNING @@ -79,16 +78,9 @@ __all__ = ( # This relies on each of the submodules having an __all__ variable. from .base_events import * from .coroutines import * - from .events import * # comment here -- - from .futures import * - from .locks import * # comment here - from .protocols import * -- - from ..runners import * # comment here - from ..queues import * +@@ -22,33 +23,16 @@ from ..streams import * -- + from some_library import ( - Just, - Enough, @@ -111,7 +103,7 @@ __all__ = ( -) +from name_of_a_company.extremely_long_project_name.component.ttypes import CuteLittleServiceHandlerFactoryyy from name_of_a_company.extremely_long_project_name.extremely_long_component_name.ttypes import * -- + from .a.b.c.subprocess import * -from . import tasks -from . import A, B, C @@ -119,20 +111,20 @@ __all__ = ( - SomeVeryLongNameAndAllOfItsAdditionalLetters1, - SomeVeryLongNameAndAllOfItsAdditionalLetters2, -) -- +from . import (tasks) +from . import (A, B, C) +from . import SomeVeryLongNameAndAllOfItsAdditionalLetters1, \ + SomeVeryLongNameAndAllOfItsAdditionalLetters2 + __all__ = ( base_events.__all__ - + coroutines.__all__ ``` ## Ruff Output ```py """The asyncio package, tracking PEP 3156.""" + # flake8: noqa from logging import ( @@ -146,22 +138,27 @@ import sys from .base_events import * from .coroutines import * from .events import * # comment here + from .futures import * from .locks import * # comment here from .protocols import * + from ..runners import * # comment here from ..queues import * from ..streams import * + from some_library import ( Just, Enough, Libraries, To, Fit, In, This, Nice, Split, Which, We, No, Longer, Use ) from name_of_a_company.extremely_long_project_name.component.ttypes import CuteLittleServiceHandlerFactoryyy from name_of_a_company.extremely_long_project_name.extremely_long_component_name.ttypes import * + from .a.b.c.subprocess import * from . import (tasks) from . import (A, B, C) from . import SomeVeryLongNameAndAllOfItsAdditionalLetters1, \ SomeVeryLongNameAndAllOfItsAdditionalLetters2 + __all__ = ( base_events.__all__ + coroutines.__all__ diff --git a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__power_op_spacing_py.snap b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__power_op_spacing_py.snap index e2e7b79f7ee9a0..4f258ac88839ad 100644 --- a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__power_op_spacing_py.snap +++ b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__power_op_spacing_py.snap @@ -76,34 +76,20 @@ return np.divide( ```diff --- Black +++ Ruff -@@ -1,16 +1,10 @@ +@@ -1,10 +1,10 @@ def function(**kwargs): t = a**2 + b**3 - return t**2 -- -- + return t ** 2 + + def function_replace_spaces(**kwargs): - t = a**2 + b**3 + c**4 -- -- + t = a **2 + b** 3 + c ** 4 + + def function_dont_replace_spaces(): - {**a, **b, **c} -- -- - a = 5**~4 - b = 5 ** f() - c = -(5**2) -@@ -29,7 +23,6 @@ - p = {(k, k**2): v**2 for k, v in pairs} - q = [10**i for i in range(6)] - r = x**y -- - a = 5.0**~4.0 - b = 5.0 ** f() - c = -(5.0**2.0) -@@ -47,8 +40,6 @@ +@@ -47,8 +47,6 @@ o = settings(max_examples=10**6.0) p = {(k, k**2): v**2.0 for k, v in pairs} q = [10.5**i for i in range(6)] @@ -112,14 +98,6 @@ return np.divide( # WE SHOULD DEFINITELY NOT EAT THESE COMMENTS (https://github.com/psf/black/issues/2873) if hasattr(view, "sum_of_weights"): return np.divide( # type: ignore[no-any-return] -@@ -57,7 +48,6 @@ - out=np.full(view.sum_of_weights.shape, np.nan), # type: ignore[union-attr] - where=view.sum_of_weights**2 > view.sum_of_weights_squared, # type: ignore[union-attr] - ) -- - return np.divide( - where=view.sum_of_weights_of_weight_long**2 > view.sum_of_weights_squared, # type: ignore - ) ``` ## Ruff Output @@ -128,10 +106,16 @@ return np.divide( def function(**kwargs): t = a**2 + b**3 return t ** 2 + + def function_replace_spaces(**kwargs): t = a **2 + b** 3 + c ** 4 + + def function_dont_replace_spaces(): {**a, **b, **c} + + a = 5**~4 b = 5 ** f() c = -(5**2) @@ -150,6 +134,7 @@ o = settings(max_examples=10**6) p = {(k, k**2): v**2 for k, v in pairs} q = [10**i for i in range(6)] r = x**y + a = 5.0**~4.0 b = 5.0 ** f() c = -(5.0**2.0) @@ -175,6 +160,7 @@ if hasattr(view, "sum_of_weights"): out=np.full(view.sum_of_weights.shape, np.nan), # type: ignore[union-attr] where=view.sum_of_weights**2 > view.sum_of_weights_squared, # type: ignore[union-attr] ) + return np.divide( where=view.sum_of_weights_of_weight_long**2 > view.sum_of_weights_squared, # type: ignore ) diff --git a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__remove_await_parens_py.snap b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__remove_await_parens_py.snap index 603cab0375df28..42f7589dcdae0d 100644 --- a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__remove_await_parens_py.snap +++ b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__remove_await_parens_py.snap @@ -94,56 +94,49 @@ async def main(): ```diff --- Black +++ Ruff -@@ -1,93 +1,64 @@ - import asyncio -- -- - # Control example - async def main(): - await asyncio.sleep(1) -- -- +@@ -8,59 +8,64 @@ + # Remove brackets for short coroutine/task async def main(): - await asyncio.sleep(1) -- -- + await (asyncio.sleep(1)) + + async def main(): - await asyncio.sleep(1) -- -- + await ( + asyncio.sleep(1) + ) + + async def main(): - await asyncio.sleep(1) -- -- + await (asyncio.sleep(1) + ) + + # Check comments async def main(): - await asyncio.sleep(1) # Hello -- -- + await ( # Hello + asyncio.sleep(1) + ) + + async def main(): - await asyncio.sleep(1) # Hello -- -- + await ( + asyncio.sleep(1) # Hello + ) + + async def main(): - await asyncio.sleep(1) # Hello -- -- + await ( + asyncio.sleep(1) + ) + + # Long lines async def main(): - await asyncio.gather( @@ -155,9 +148,9 @@ async def main(): - asyncio.sleep(1), - asyncio.sleep(1), - ) -- -- + await asyncio.gather(asyncio.sleep(1), asyncio.sleep(1), asyncio.sleep(1), asyncio.sleep(1), asyncio.sleep(1), asyncio.sleep(1), asyncio.sleep(1)) + + # Same as above but with magic trailing comma in function async def main(): - await asyncio.gather( @@ -169,14 +162,12 @@ async def main(): - asyncio.sleep(1), - asyncio.sleep(1), - ) -- -- + await asyncio.gather(asyncio.sleep(1), asyncio.sleep(1), asyncio.sleep(1), asyncio.sleep(1), asyncio.sleep(1), asyncio.sleep(1), asyncio.sleep(1),) + + # Cr@zY Br@ck3Tz async def main(): - await black(1) -- -- + await ( + ((((((((((((( + ((( ((( @@ -190,74 +181,81 @@ async def main(): + ))) ))) + ))))))))))))) + ) + + # Keep brackets around non power operations and nested awaits - async def main(): - await (set_of_tasks | other_set) -- -- - async def main(): - await (await asyncio.sleep(1)) -- -- - # It's awaits all the way down... - async def main(): - await (await x) -- -- - async def main(): - await (yield x) -- -- +@@ -82,11 +87,11 @@ + + async def main(): - await (await asyncio.sleep(1)) -- -- + await (await (asyncio.sleep(1))) + + async def main(): - await (await (await (await (await asyncio.sleep(1))))) -- -- + await (await (await (await (await (asyncio.sleep(1)))))) + + async def main(): - await (yield) ``` ## Ruff Output ```py import asyncio + + # Control example async def main(): await asyncio.sleep(1) + + # Remove brackets for short coroutine/task async def main(): await (asyncio.sleep(1)) + + async def main(): await ( asyncio.sleep(1) ) + + async def main(): await (asyncio.sleep(1) ) + + # Check comments async def main(): await ( # Hello asyncio.sleep(1) ) + + async def main(): await ( asyncio.sleep(1) # Hello ) + + async def main(): await ( asyncio.sleep(1) ) + + # Long lines async def main(): await asyncio.gather(asyncio.sleep(1), asyncio.sleep(1), asyncio.sleep(1), asyncio.sleep(1), asyncio.sleep(1), asyncio.sleep(1), asyncio.sleep(1)) + + # Same as above but with magic trailing comma in function async def main(): await asyncio.gather(asyncio.sleep(1), asyncio.sleep(1), asyncio.sleep(1), asyncio.sleep(1), asyncio.sleep(1), asyncio.sleep(1), asyncio.sleep(1),) + + # Cr@zY Br@ck3Tz async def main(): await ( @@ -273,20 +271,34 @@ async def main(): ))) ))) ))))))))))))) ) + + # Keep brackets around non power operations and nested awaits async def main(): await (set_of_tasks | other_set) + + async def main(): await (await asyncio.sleep(1)) + + # It's awaits all the way down... async def main(): await (await x) + + async def main(): await (yield x) + + async def main(): await (await (asyncio.sleep(1))) + + async def main(): await (await (await (await (await (asyncio.sleep(1)))))) + + async def main(): await (yield) ``` diff --git a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__remove_except_parens_py.snap b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__remove_except_parens_py.snap index f7724c3116ffba..7f435c1e2fa088 100644 --- a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__remove_except_parens_py.snap +++ b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__remove_except_parens_py.snap @@ -48,7 +48,7 @@ except (some.really.really.really.looooooooooooooooooooooooooooooooong.module.ov ```diff --- Black +++ Ruff -@@ -1,42 +1,25 @@ +@@ -1,42 +1,27 @@ # These brackets are redundant, therefore remove. try: a.something @@ -78,7 +78,7 @@ except (some.really.really.really.looooooooooooooooooooooooooooooooong.module.ov -) as err: +except (some.really.really.really.looooooooooooooooooooooooooooooooong.module.over89.chars.Error) as err: raise err -- + try: a.something -except ( @@ -86,7 +86,7 @@ except (some.really.really.really.looooooooooooooooooooooooooooooooong.module.ov -) as err: +except (some.really.really.really.looooooooooooooooooooooooooooooooong.module.over89.chars.Error,) as err: raise err -- + try: a.something -except ( @@ -117,10 +117,12 @@ try: a.something except (some.really.really.really.looooooooooooooooooooooooooooooooong.module.over89.chars.Error) as err: raise err + try: a.something except (some.really.really.really.looooooooooooooooooooooooooooooooong.module.over89.chars.Error,) as err: raise err + try: a.something except (some.really.really.really.looooooooooooooooooooooooooooooooong.module.over89.chars.Error, some.really.really.really.looooooooooooooooooooooooooooooooong.module.over89.chars.Error) as err: diff --git a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__remove_for_brackets_py.snap b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__remove_for_brackets_py.snap index df7d50d6f2baa2..d432c040c7910d 100644 --- a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__remove_for_brackets_py.snap +++ b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__remove_for_brackets_py.snap @@ -32,7 +32,7 @@ for (((((k, v))))) in d.items(): ```diff --- Black +++ Ruff -@@ -1,27 +1,15 @@ +@@ -1,27 +1,16 @@ # Only remove tuple brackets after `for` -for k, v in d.items(): +for (k, v) in d.items(): @@ -50,7 +50,7 @@ for (((((k, v))))) in d.items(): -) in d.items(): +for (why_would_anyone_choose_to_name_a_loop_variable_with_a_name_this_long, i_dont_know_but_we_should_still_check_the_behaviour_if_they_do) in d.items(): print(k, v) -- + -for ( - k, - v, @@ -79,6 +79,7 @@ for module in (core, _unicodefun): # Brackets remain for long for loop lines for (why_would_anyone_choose_to_name_a_loop_variable_with_a_name_this_long, i_dont_know_but_we_should_still_check_the_behaviour_if_they_do) in d.items(): print(k, v) + for (k, v) in dfkasdjfldsjflkdsjflkdsjfdslkfjldsjfgkjdshgkljjdsfldgkhsdofudsfudsofajdslkfjdslkfjldisfjdffjsdlkfjdlkjjkdflskadjldkfjsalkfjdasj.items(): print(k, v) # Test deeply nested brackets diff --git a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__remove_newline_after_code_block_open_py.snap b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__remove_newline_after_code_block_open_py.snap index bb3d5adbec618e..f632858d07357f 100644 --- a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__remove_newline_after_code_block_open_py.snap +++ b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__remove_newline_after_code_block_open_py.snap @@ -121,104 +121,107 @@ with open("/path/to/file.txt", mode="r") as read_file: ```diff --- Black +++ Ruff -@@ -1,78 +1,74 @@ - import random -- -- +@@ -2,20 +2,26 @@ + + def foo1(): -- print("The newline above me should be deleted!") -- ++ + print("The newline above me should be deleted!") + -+ print("The newline above me should be deleted!") def foo2(): -- print("All the newlines above me should be deleted!") ++ ++ ++ + print("All the newlines above me should be deleted!") -+ -+ print("All the newlines above me should be deleted!") def foo3(): + print("No newline above me!") print("There is a newline above me, and that's OK!") -+def foo4(): -- --def foo4(): + + def foo4(): ++ # There is a comment here print("The newline above me should not be deleted!") -- -- +@@ -23,27 +29,39 @@ + class Foo: def bar(self): + print("The newline above me should be deleted!") -- -- - for i in range(5): -- print(f"{i}) The line above me should be removed!") -- -+ print(f"{i}) The line above me should be removed!") + for i in range(5): -- print(f"{i}) The lines above me should be removed!") ++ + print(f"{i}) The line above me should be removed!") + for i in range(5): + -+ print(f"{i}) The lines above me should be removed!") ++ ++ + print(f"{i}) The lines above me should be removed!") + + for i in range(5): + for j in range(7): + print(f"{i}) The lines above me should be removed!") -+if random.randint(0, 3) == 0: -- -+ print("The new line above me is about to be removed!") + if random.randint(0, 3) == 0: -- print("The new line above me is about to be removed!") ++ + print("The new line above me is about to be removed!") + + if random.randint(0, 3) == 0: ++ ++ ++ ++ + print("The new lines above me is about to be removed!") --if random.randint(0, 3) == 0: -- print("The new lines above me is about to be removed!") +@@ -53,26 +71,38 @@ -+ print("The new lines above me is about to be removed!") - if random.randint(0, 3) == 0: - if random.uniform(0, 1) > 0.5: - print("Two lines above me are about to be removed!") -- -+while True: -+ print("The newline above me should be deleted!") while True: -- print("The newline above me should be deleted!") ++ + print("The newline above me should be deleted!") --while True: + while True: ++ ++ + print("The newlines above me should be deleted!") -+while True: -- --while True: + + while True: ++ while False: -- print("The newlines above me should be deleted!") -- ++ + print("The newlines above me should be deleted!") -+ print("The newlines above me should be deleted!") - with open("/path/to/file.txt", mode="w") as file: -- file.write("The new line above me is about to be removed!") -- -+ file.write("The new line above me is about to be removed!") with open("/path/to/file.txt", mode="w") as file: -- file.write("The new lines above me is about to be removed!") ++ + file.write("The new line above me is about to be removed!") + with open("/path/to/file.txt", mode="w") as file: + -+ file.write("The new lines above me is about to be removed!") ++ ++ + file.write("The new lines above me is about to be removed!") + + with open("/path/to/file.txt", mode="r") as read_file: + with open("/path/to/output_file.txt", mode="w") as write_file: @@ -230,74 +233,108 @@ with open("/path/to/file.txt", mode="r") as read_file: ```py import random + + def foo1(): print("The newline above me should be deleted!") + + def foo2(): print("All the newlines above me should be deleted!") + + def foo3(): print("No newline above me!") print("There is a newline above me, and that's OK!") + + def foo4(): # There is a comment here print("The newline above me should not be deleted!") + + class Foo: def bar(self): print("The newline above me should be deleted!") + + for i in range(5): print(f"{i}) The line above me should be removed!") + + for i in range(5): print(f"{i}) The lines above me should be removed!") + + for i in range(5): for j in range(7): print(f"{i}) The lines above me should be removed!") + + if random.randint(0, 3) == 0: print("The new line above me is about to be removed!") + + if random.randint(0, 3) == 0: print("The new lines above me is about to be removed!") + + if random.randint(0, 3) == 0: if random.uniform(0, 1) > 0.5: print("Two lines above me are about to be removed!") + + while True: print("The newline above me should be deleted!") + + while True: print("The newlines above me should be deleted!") + + while True: while False: print("The newlines above me should be deleted!") + + with open("/path/to/file.txt", mode="w") as file: file.write("The new line above me is about to be removed!") + + with open("/path/to/file.txt", mode="w") as file: file.write("The new lines above me is about to be removed!") + + with open("/path/to/file.txt", mode="r") as read_file: with open("/path/to/output_file.txt", mode="w") as write_file: diff --git a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__remove_parens_py.snap b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__remove_parens_py.snap index d06c27e3a0abdd..7b2de231ae843f 100644 --- a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__remove_parens_py.snap +++ b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__remove_parens_py.snap @@ -68,19 +68,15 @@ def example8(): ```diff --- Black +++ Ruff -@@ -1,85 +1,34 @@ +@@ -1,5 +1,5 @@ -x = 1 -x = 1.2 -- +x = (1) +x = (1.2) + data = ( "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" - ).encode() -- -- - async def show_status(): - while True: +@@ -11,75 +11,47 @@ try: if report_host: data = ( @@ -90,52 +86,52 @@ def example8(): + ).encode() except Exception as e: pass -- -- + + def example(): - return "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" -- -- + return (("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")) + + def example1(): - return 1111111111111111111111111111111111111111111111111111111111111111111111111111111111111 -- -- + return ((1111111111111111111111111111111111111111111111111111111111111111111111111111111111111)) + + def example1point5(): - return 1111111111111111111111111111111111111111111111111111111111111111111111111111111111111 -- -- + return ((((((1111111111111111111111111111111111111111111111111111111111111111111111111111111111111)))))) + + def example2(): - return ( - "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" - ) -- -- + return (("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")) + + def example3(): - return ( - 1111111111111111111111111111111111111111111111111111111111111111111111111111111 - ) -- -- + return ((1111111111111111111111111111111111111111111111111111111111111111111111111111111)) + + def example4(): - return True -- -- + return ((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((True)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))) + + def example5(): - return () -- -- + return ((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((())))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))) + + def example6(): - return {a: a for a in [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17]} -- -- + return ((((((((({a:a for a in [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17]}))))))))) + + def example7(): - return { - a: a @@ -162,9 +158,9 @@ def example8(): - 20000000000000000000, - ] - } -- -- + return ((((((((({a:a for a in [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20000000000000000000]}))))))))) + + def example8(): - return None + return (((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((None))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))) @@ -175,9 +171,12 @@ def example8(): ```py x = (1) x = (1.2) + data = ( "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" ).encode() + + async def show_status(): while True: try: @@ -187,24 +186,44 @@ async def show_status(): ).encode() except Exception as e: pass + + def example(): return (("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")) + + def example1(): return ((1111111111111111111111111111111111111111111111111111111111111111111111111111111111111)) + + def example1point5(): return ((((((1111111111111111111111111111111111111111111111111111111111111111111111111111111111111)))))) + + def example2(): return (("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")) + + def example3(): return ((1111111111111111111111111111111111111111111111111111111111111111111111111111111)) + + def example4(): return ((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((True)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))) + + def example5(): return ((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((())))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))) + + def example6(): return ((((((((({a:a for a in [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17]}))))))))) + + def example7(): return ((((((((({a:a for a in [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20000000000000000000]}))))))))) + + def example8(): return (((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((None))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))) ``` diff --git a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__return_annotation_brackets_py.snap b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__return_annotation_brackets_py.snap index f80e25a7c9d582..d09d9dfaa79517 100644 --- a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__return_annotation_brackets_py.snap +++ b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__return_annotation_brackets_py.snap @@ -101,82 +101,80 @@ def foo() -> tuple[int, int, int,]: ```diff --- Black +++ Ruff -@@ -1,120 +1,70 @@ +@@ -1,33 +1,41 @@ # Control def double(a: int) -> int: - return 2 * a -- -- + return 2*a + + # Remove the brackets -def double(a: int) -> int: - return 2 * a -- -- +def double(a: int) -> (int): + return 2*a + + # Some newline variations -def double(a: int) -> int: - return 2 * a -- -- --def double(a: int) -> int: -- return 2 * a -- -- --def double(a: int) -> int: -- return 2 * a -- -- +def double(a: int) -> ( + int): + return 2*a + + +-def double(a: int) -> int: +- return 2 * a +def double(a: int) -> (int +): + return 2*a + + +-def double(a: int) -> int: +- return 2 * a +def double(a: int) -> ( + int +): + return 2*a + + # Don't lose the comments -def double(a: int) -> int: # Hello - return 2 * a -- -- --def double(a: int) -> int: # Hello -- return 2 * a -- -- +def double(a: int) -> ( # Hello + int +): + return 2*a + + +-def double(a: int) -> int: # Hello +- return 2 * a +def double(a: int) -> ( + int # Hello +): + return 2*a + + # Really long annotations - def foo() -> ( - intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds - ): +@@ -37,84 +45,62 @@ return 2 -- -- + + -def foo() -> ( - intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds -): +def foo() -> intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds: return 2 -- -- + + -def foo() -> ( - intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds - | intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds -): +def foo() -> intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds | intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds: return 2 -- -- + + -def foo( - a: int, - b: int, @@ -184,8 +182,8 @@ def foo() -> tuple[int, int, int,]: -) -> intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds: +def foo(a: int, b: int, c: int,) -> intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds: return 2 -- -- + + -def foo( - a: int, - b: int, @@ -196,8 +194,8 @@ def foo() -> tuple[int, int, int,]: -): +def foo(a: int, b: int, c: int,) -> intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds | intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds: return 2 -- -- + + # Split args but no need to split return -def foo( - a: int, @@ -206,20 +204,18 @@ def foo() -> tuple[int, int, int,]: -) -> int: +def foo(a: int, b: int, c: int,) -> int: return 2 -- -- + + # Deeply nested brackets # with *interesting* spacing -def double(a: int) -> int: - return 2 * a -- -- --def double(a: int) -> int: -- return 2 * a -- -- +def double(a: int) -> (((((int))))): + return 2*a + + +-def double(a: int) -> int: +- return 2 * a +def double(a: int) -> ( + ( ( + ((int) @@ -228,6 +224,8 @@ def foo() -> tuple[int, int, int,]: + ) + ): + return 2*a + + def foo() -> ( + ( ( intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds @@ -235,26 +233,27 @@ def foo() -> tuple[int, int, int,]: +) +)): return 2 -- -- + + # Return type with commas -def foo() -> tuple[int, int, int]: -- return 2 -- -- - def foo() -> ( ++def foo() -> ( ++ tuple[int, int, int] ++): + return 2 + + +-def foo() -> ( - tuple[ - loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong, - loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong, - loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong, - ] -+ tuple[int, int, int] - ): - return 2 -- -- +-): +def foo() -> tuple[loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong, loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong, loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong]: -+ return 2 + return 2 + + # Magic trailing comma example -def foo() -> ( - tuple[ @@ -273,49 +272,77 @@ def foo() -> tuple[int, int, int,]: # Control def double(a: int) -> int: return 2*a + + # Remove the brackets def double(a: int) -> (int): return 2*a + + # Some newline variations def double(a: int) -> ( int): return 2*a + + def double(a: int) -> (int ): return 2*a + + def double(a: int) -> ( int ): return 2*a + + # Don't lose the comments def double(a: int) -> ( # Hello int ): return 2*a + + def double(a: int) -> ( int # Hello ): return 2*a + + # Really long annotations def foo() -> ( intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds ): return 2 + + def foo() -> intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds: return 2 + + def foo() -> intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds | intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds: return 2 + + def foo(a: int, b: int, c: int,) -> intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds: return 2 + + def foo(a: int, b: int, c: int,) -> intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds | intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds: return 2 + + # Split args but no need to split return def foo(a: int, b: int, c: int,) -> int: return 2 + + # Deeply nested brackets # with *interesting* spacing def double(a: int) -> (((((int))))): return 2*a + + def double(a: int) -> ( ( ( ((int) @@ -324,19 +351,27 @@ def double(a: int) -> ( ) ): return 2*a + + def foo() -> ( ( ( intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds ) )): return 2 + + # Return type with commas def foo() -> ( tuple[int, int, int] ): return 2 + + def foo() -> tuple[loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong, loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong, loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong]: return 2 + + # Magic trailing comma example def foo() -> tuple[int, int, int,]: return 2 diff --git a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__skip_magic_trailing_comma_py.snap b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__skip_magic_trailing_comma_py.snap index fbac7ed57e9385..26cfa4facad10f 100644 --- a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__skip_magic_trailing_comma_py.snap +++ b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__skip_magic_trailing_comma_py.snap @@ -60,7 +60,7 @@ func( ```diff --- Black +++ Ruff -@@ -1,25 +1,40 @@ +@@ -1,25 +1,43 @@ # We should not remove the trailing comma in a single-element subscript. a: tuple[int,] b = tuple[int,] @@ -86,12 +86,6 @@ func( - # Trailing commas in multiple chained non-nested parens. -zero(one).two(three).four(five) -- --func1(arg1).func2(arg2).func3(arg3).func4(arg4).func5(arg5) -- --(a, b, c, d) = func1(arg1) and func2(arg2) -- --func(argument1, (one, two), argument4, argument5, argument6) +zero( + one, +).two( @@ -99,7 +93,11 @@ func( +).four( + five, +) + +-func1(arg1).func2(arg2).func3(arg3).func4(arg4).func5(arg5) +func1(arg1).func2(arg2,).func3(arg3).func4(arg4,).func5(arg5) + +-(a, b, c, d) = func1(arg1) and func2(arg2) +( + a, + b, @@ -108,6 +106,8 @@ func( +) = func1( + arg1 +) and func2(arg2) + +-func(argument1, (one, two), argument4, argument5, argument6) +func( + argument1, + ( @@ -144,7 +144,9 @@ zero( ).four( five, ) + func1(arg1).func2(arg2,).func3(arg3).func4(arg4,).func5(arg5) + ( a, b, @@ -153,6 +155,7 @@ func1(arg1).func2(arg2,).func3(arg3).func4(arg4,).func5(arg5) ) = func1( arg1 ) and func2(arg2) + func( argument1, ( diff --git a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__slices_py.snap b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__slices_py.snap index ee4cb215cce7c3..902e4035e2ec4e 100644 --- a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__slices_py.snap +++ b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__slices_py.snap @@ -76,35 +76,7 @@ x[ ```diff --- Black +++ Ruff -@@ -17,19 +17,14 @@ - slice[not so_simple : 1 < val <= 10] - slice[(1 for i in range(42)) : x] - slice[:: [i for i in range(42)]] -- -- - async def f(): - slice[await x : [i async for i in arange(42)] : 42] -- -- - # These are from PEP-8: - ham[1:9], ham[1:9:3], ham[:9:3], ham[1::3], ham[1:9:] - 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 -@@ -46,7 +41,6 @@ - # C - 3 - ] -- - slice[ - # A - 1 -@@ -56,4 +50,8 @@ +@@ -56,4 +56,8 @@ # C 4 ] @@ -138,14 +110,19 @@ slice[1 or 2 : True and False] slice[not so_simple : 1 < val <= 10] slice[(1 for i in range(42)) : x] slice[:: [i for i in range(42)]] + + async def f(): slice[await x : [i async for i in arange(42)] : 42] + + # These are from PEP-8: ham[1:9], ham[1:9:3], ham[:9:3], ham[1::3], ham[1:9:] 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 @@ -162,6 +139,7 @@ slice[ # C 3 ] + slice[ # A 1 diff --git a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__string_prefixes_py.snap b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__string_prefixes_py.snap index be3dbc6901f9cf..07e263b90e0772 100644 --- a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__string_prefixes_py.snap +++ b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__string_prefixes_py.snap @@ -33,7 +33,7 @@ def docstring_multiline(): ```diff --- Black +++ Ruff -@@ -1,19 +1,14 @@ +@@ -1,13 +1,13 @@ #!/usr/bin/env python3 name = "Łukasz" @@ -44,20 +44,14 @@ def docstring_multiline(): +(b"", B"") +(u"", U"") (r"", R"") -- + -(rf"", rf"", Rf"", Rf"", rf"", rf"", Rf"", Rf"") -(rb"", rb"", Rb"", Rb"", rb"", rb"", Rb"", Rb"") -- -- +(rf"", fr"", Rf"", fR"", rF"", Fr"", RF"", FR"") +(rb"", br"", Rb"", bR"", rB"", Br"", RB"", BR"") + + def docstring_singleline(): - R"""2020 was one hell of a year. The good news is that we were able to""" -- -- - def docstring_multiline(): - R""" - clear out all of the issues opened in that time :p ``` ## Ruff Output @@ -70,10 +64,15 @@ name = "Łukasz" (b"", B"") (u"", U"") (r"", R"") + (rf"", fr"", Rf"", fR"", rF"", Fr"", RF"", FR"") (rb"", br"", Rb"", bR"", rB"", Br"", RB"", BR"") + + def docstring_singleline(): R"""2020 was one hell of a year. The good news is that we were able to""" + + def docstring_multiline(): R""" clear out all of the issues opened in that time :p diff --git a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__torture_py.snap b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__torture_py.snap index 304ee0a3cb6126..95a7d919071269 100644 --- a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__torture_py.snap +++ b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__torture_py.snap @@ -42,15 +42,15 @@ assert ( ```diff --- Black +++ Ruff -@@ -1,58 +1,25 @@ +@@ -1,58 +1,33 @@ importA -( - () - << 0 - ** 101234234242352525425252352352525234890264906820496920680926538059059209922523523525 -) # -- +() << 0 ** 101234234242352525425252352352525234890264906820496920680926538059059209922523523525 # + assert sort_by_dependency( { - "1": {"2", "3"}, @@ -64,13 +64,13 @@ assert ( + "2a": set(), "2b": set(), "3a": set(), "3b": set() } ) == ["2a", "2b", "2", "3a", "3b", "3", "1"] -- + importA 0 -0 ^ 0 # -- -- +0^0 # + + class A: def foo(self): for _ in range(10): @@ -78,9 +78,9 @@ assert ( + aaaaaaaaaaaaaaaaaaa = bbbbbbbbbbbbbbb.cccccccccc( # pylint: disable=no-member xxxxxxxxxxxx - ) # pylint: disable=no-member -- -- + ) + + def test(self, othr): - return 1 == 2 and ( - name, @@ -101,15 +101,15 @@ assert ( - othr.meta_data, - othr.schedule, - ) -- -- ++ return (1 == 2 and ++ (name, description, self.default, self.selected, self.auto_generated, self.parameters, self.meta_data, self.schedule) == ++ (name, description, othr.default, othr.selected, othr.auto_generated, othr.parameters, othr.meta_data, othr.schedule)) + + -assert a_function( - very_long_arguments_that_surpass_the_limit, - which_is_eighty_eight_in_this_case_plus_a_bit_more, -) == {"x": "this need to pass the line limit as well", "b": "but only by a little bit"} -+ return (1 == 2 and -+ (name, description, self.default, self.selected, self.auto_generated, self.parameters, self.meta_data, self.schedule) == -+ (name, description, othr.default, othr.selected, othr.auto_generated, othr.parameters, othr.meta_data, othr.schedule)) +assert ( + a_function(very_long_arguments_that_surpass_the_limit, which_is_eighty_eight_in_this_case_plus_a_bit_more) + == {"x": "this need to pass the line limit as well", "b": "but only by a little bit"} @@ -121,25 +121,33 @@ assert ( ```py importA () << 0 ** 101234234242352525425252352352525234890264906820496920680926538059059209922523523525 # + assert sort_by_dependency( { "1": {"2", "3"}, "2": {"2a", "2b"}, "3": {"3a", "3b"}, "2a": set(), "2b": set(), "3a": set(), "3b": set() } ) == ["2a", "2b", "2", "3a", "3b", "3", "1"] + importA 0 0^0 # + + class A: def foo(self): for _ in range(10): aaaaaaaaaaaaaaaaaaa = bbbbbbbbbbbbbbb.cccccccccc( # pylint: disable=no-member xxxxxxxxxxxx ) + + def test(self, othr): return (1 == 2 and (name, description, self.default, self.selected, self.auto_generated, self.parameters, self.meta_data, self.schedule) == (name, description, othr.default, othr.selected, othr.auto_generated, othr.parameters, othr.meta_data, othr.schedule)) + + assert ( a_function(very_long_arguments_that_surpass_the_limit, which_is_eighty_eight_in_this_case_plus_a_bit_more) == {"x": "this need to pass the line limit as well", "b": "but only by a little bit"} diff --git a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__trailing_comma_optional_parens1_py.snap b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__trailing_comma_optional_parens1_py.snap index 7fea6d8abe191e..a6989d984aabf4 100644 --- a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__trailing_comma_optional_parens1_py.snap +++ b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__trailing_comma_optional_parens1_py.snap @@ -38,7 +38,7 @@ class A: ```diff --- Black +++ Ruff -@@ -1,29 +1,17 @@ +@@ -1,18 +1,11 @@ -if e1234123412341234.winerror not in ( - _winapi.ERROR_SEM_TIMEOUT, - _winapi.ERROR_PIPE_BUSY, @@ -46,7 +46,7 @@ class A: +if e1234123412341234.winerror not in (_winapi.ERROR_SEM_TIMEOUT, + _winapi.ERROR_PIPE_BUSY) or _check_timeout(t): pass -- + if x: if y: - new_id = ( @@ -56,23 +56,20 @@ class A: - ) - + 1 - ) -- -- + new_id = max(Vegetable.objects.order_by('-id')[0].id, + Mineral.objects.order_by('-id')[0].id) + 1 + + class X: - def get_help_text(self): - return ngettext( +@@ -21,7 +14,7 @@ "Your password must contain at least %(min_length)d character.", "Your password must contain at least %(min_length)d characters.", self.min_length, - ) % {"min_length": self.min_length} -- -- + ) % {'min_length': self.min_length} + + class A: - def b(self): - if self.connection.mysql_is_mariadb and ( ``` ## Ruff Output @@ -81,10 +78,13 @@ class A: if e1234123412341234.winerror not in (_winapi.ERROR_SEM_TIMEOUT, _winapi.ERROR_PIPE_BUSY) or _check_timeout(t): pass + if x: if y: new_id = max(Vegetable.objects.order_by('-id')[0].id, Mineral.objects.order_by('-id')[0].id) + 1 + + class X: def get_help_text(self): return ngettext( @@ -92,6 +92,8 @@ class X: "Your password must contain at least %(min_length)d characters.", self.min_length, ) % {'min_length': self.min_length} + + class A: def b(self): if self.connection.mysql_is_mariadb and ( diff --git a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__trailing_commas_in_leading_parts_py.snap b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__trailing_commas_in_leading_parts_py.snap index 73853e4f0e32d1..eea12aab0014e2 100644 --- a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__trailing_commas_in_leading_parts_py.snap +++ b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__trailing_commas_in_leading_parts_py.snap @@ -46,7 +46,7 @@ assert xxxxxxxxx.xxxxxxxxx.xxxxxxxxx( ```diff --- Black +++ Ruff -@@ -1,30 +1,8 @@ +@@ -1,28 +1,10 @@ -zero( - one, -).two( @@ -60,12 +60,12 @@ assert xxxxxxxxx.xxxxxxxxx.xxxxxxxxx( -).func3(arg3).func4( - arg4, -).func5(arg5) -- +zero(one,).two(three,).four(five,) + +func1(arg1).func2(arg2,).func3(arg3).func4(arg4,).func5(arg5) # Inner one-element tuple shouldn't explode func1(arg1).func2(arg1, (one_tuple,)).func3(arg3) -- + -( - a, - b, @@ -74,21 +74,11 @@ assert xxxxxxxxx.xxxxxxxxx.xxxxxxxxx( -) = func1( - arg1 -) and func2(arg2) -- -- +(a, b, c, d,) = func1(arg1) and func2(arg2) + + # Example from https://github.com/psf/black/issues/3229 - def refresh_token(self, device_family, refresh_token, api_key): - return self.orchestration.refresh_token( -@@ -33,15 +11,12 @@ - }, - api_key=api_key, - )["extensions"]["sdk"]["token"] -- -- - # Edge case where a bug in a working-in-progress version of - # https://github.com/psf/black/pull/3370 causes an infinite recursion. - assert ( +@@ -41,7 +23,6 @@ long_module.long_class.long_func().another_func() == long_module.long_class.long_func()["some_key"].another_func(arg1) ) @@ -102,10 +92,14 @@ assert xxxxxxxxx.xxxxxxxxx.xxxxxxxxx( ```py zero(one,).two(three,).four(five,) + func1(arg1).func2(arg2,).func3(arg3).func4(arg4,).func5(arg5) # Inner one-element tuple shouldn't explode func1(arg1).func2(arg1, (one_tuple,)).func3(arg3) + (a, b, c, d,) = func1(arg1) and func2(arg2) + + # Example from https://github.com/psf/black/issues/3229 def refresh_token(self, device_family, refresh_token, api_key): return self.orchestration.refresh_token( @@ -114,6 +108,8 @@ def refresh_token(self, device_family, refresh_token, api_key): }, api_key=api_key, )["extensions"]["sdk"]["token"] + + # Edge case where a bug in a working-in-progress version of # https://github.com/psf/black/pull/3370 causes an infinite recursion. assert ( diff --git a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__tricky_unicode_symbols_py.snap b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__tricky_unicode_symbols_py.snap deleted file mode 100644 index 01c1dbbadd6e9d..00000000000000 --- a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__tricky_unicode_symbols_py.snap +++ /dev/null @@ -1,61 +0,0 @@ ---- -source: crates/ruff_python_formatter/src/lib.rs -expression: snapshot -input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/tricky_unicode_symbols.py ---- -## Input - -```py -ä = 1 -µ = 2 -蟒 = 3 -x󠄀 = 4 -មុ = 1 -Q̇_per_meter = 4 - -A᧚ = 3 -A፩ = 8 -``` - -## Black Differences - -```diff ---- Black -+++ Ruff -@@ -4,6 +4,5 @@ - x󠄀 = 4 - មុ = 1 - Q̇_per_meter = 4 -- - A᧚ = 3 - A፩ = 8 -``` - -## Ruff Output - -```py -ä = 1 -µ = 2 -蟒 = 3 -x󠄀 = 4 -មុ = 1 -Q̇_per_meter = 4 -A᧚ = 3 -A፩ = 8 -``` - -## Black Output - -```py -ä = 1 -µ = 2 -蟒 = 3 -x󠄀 = 4 -មុ = 1 -Q̇_per_meter = 4 - -A᧚ = 3 -A፩ = 8 -``` - - diff --git a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__tupleassign_py.snap b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__tupleassign_py.snap index a1a1c9cf2fd1ff..084d542640d1d2 100644 --- a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__tupleassign_py.snap +++ b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__tupleassign_py.snap @@ -20,7 +20,7 @@ this_will_be_wrapped_in_parens, = struct.unpack(b"12345678901234567890") ```diff --- Black +++ Ruff -@@ -1,12 +1,5 @@ +@@ -1,12 +1,6 @@ # This is a standalone comment. -( - sdfjklsdfsjldkflkjsf, @@ -32,8 +32,8 @@ this_will_be_wrapped_in_parens, = struct.unpack(b"12345678901234567890") +sdfjklsdfsjldkflkjsf, sdfjsdfjlksdljkfsdlkf, sdfsdjfklsdfjlksdljkf, sdsfsdfjskdflsfsdf = 1, 2, 3 # This is as well. -(this_will_be_wrapped_in_parens,) = struct.unpack(b"12345678901234567890") -- +this_will_be_wrapped_in_parens, = struct.unpack(b"12345678901234567890") + (a,) = call() ``` @@ -44,6 +44,7 @@ this_will_be_wrapped_in_parens, = struct.unpack(b"12345678901234567890") sdfjklsdfsjldkflkjsf, sdfjsdfjlksdljkfsdlkf, sdfsdjfklsdfjlksdljkf, sdsfsdfjskdflsfsdf = 1, 2, 3 # This is as well. this_will_be_wrapped_in_parens, = struct.unpack(b"12345678901234567890") + (a,) = call() ```